* configure: Regenerate.
gold/
* nacl.cc: New file.
* nacl.h: New file.
* Makefile.am (CCFILES, HFILES): Add them.
* Makefile.in: Regenerate.
* i386.cc (Output_data_plt_i386_nacl): New class.
(Output_data_plt_i386_nacl_exec): New class.
(Output_data_plt_i386_nacl_dyn): New class.
(Target_i386_nacl): New class.
(Target_selector_i386_nacl): New class.
(target_selector_i386): Use it instead of Target_selector_i386.
* x86_64.cc (Output_data_plt_x86_64_nacl): New class.
(Target_x86_64_nacl): New class.
(Target_selector_x86_64_nacl): New class.
(target_selector_x86_64, target_selector_x32): Use it instead of
Target_selector_x86_64.
* arm.cc (Output_data_plt_arm_nacl): New class.
(Target_arm_nacl): New class.
(Target_selector_arm_nacl): New class.
(target_selector_arm, target_selector_armbe): Use it instead of
Target_selector_arm.
* target-select.cc (select_target): Take new Input_file* and off_t
arguments, pass them on to recognize method of selector.
* object.cc (make_elf_sized_object): Update caller.
* parameters.cc (parameters_force_valid_target): Likewise.
* incremental.cc (make_sized_incremental_binary): Likewise.
* target-select.h: Update decl.
(Target_selector::recognize): Take new Input_file* argument,
pass it on to do_recognize.
(Target_selector::do_recognize): Take new Input_file* argument.
* freebsd.h (Target_selector_freebsd::do_recognize): Likewise.
* powerpc.cc (Target_selector_powerpc::do_recognize): Likewise.
* sparc.cc (Target_selector_sparc::do_recognize): Likewise.
* testsuite/testfile.cc (Target_selector::do_recognize): Likewise.
* target.h (Target::Target_info): New members isolate_execinstr
and rosegment_gap.
(Target::isolate_execinstr, Target::rosegment_gap): New methods.
* arm.cc (Target_arm::arm_info): Update initializer.
* i386.cc (Target_i386::i386_info): Likewise.
* powerpc.cc (Target_powerpc::powerpc_info): Likewise.
* sparc.cc (Target_sparc::sparc_info): Likewise.
* x86_64.cc (Target_x86_64::x86_64_info): Likewise.
* testsuite/testfile.cc (Target_test::test_target_info): Likewise.
* layout.cc (Layout::attach_allocated_section_to_segment):
Take new const Target* argument. If target->isolate_execinstr(), act
like --rosegment.
(Layout::find_first_load_seg): Take new const Target* argument;
if target->isolate_execinstr(), reject PF_X segments.
(Layout::relaxation_loop_body): Update caller.
(Layout::set_segment_offsets): If target->isolate_execinstr(),
reset file offset to zero when we hit LOAD_SEG, and then do a second
loop over the segments before LOAD_SEG to reassign offsets after
addresses have been determined. Handle target->rosegment_gap().
(Layout::attach_section_to_segment): Take new const Target* argument;
pass it to attach_allocated_section_to_segment.
(Layout::make_output_section): Update caller.
(Layout::attach_sections_to_segments): Take new const Target* argument;
pass it to attach_section_to_segment.
* gold.cc (queue_middle_tasks): Update caller.
* layout.h (Layout): Update method decls with new arguments.
* arm.cc (Target_arm::Target_arm): Take optional argument for the
Target_info pointer to use.
(Target_arm::do_make_data_plt): New virtual method.
(Target_arm::make_data_plt): New method that calls it.
(Target_arm::make_plt_entry): Use it.
(Output_data_plt_arm::Output_data_plt_arm): Take additional argument
for the section alignment.
(Output_data_plt_arm::do_first_plt_entry_offset): New abstract virtual
method.
(Output_data_plt_arm::first_plt_entry_offset): Call it.
(Output_data_plt_arm::do_get_plt_entry_size): New abstract virtual
method.
(Output_data_plt_arm::get_plt_entry_size): Call it.
(Output_data_plt_arm::do_fill_plt_entry): New abstract virtual method.
(Output_data_plt_arm::fill_plt_entry): New method that calls it.
(Output_data_plt_arm::do_fill_first_plt_entry): New abstract virtual
method.
(Output_data_plt_arm::fill_first_plt_entry): New method that calls it.
(Output_data_plt_arm::set_final_data_size): Use get_plt_entry_size
method instead of sizeof(plt_entry).
(Output_data_plt_arm::add_entry): Likewise.
Use first_plt_entry_offset method instead of sizeof(first_plt_entry).
(Target_arm::first_plt_entry_offset): Call method on this->plt_ rather
than static method.
(Target_arm::plt_entry_size): Likewise.
(Output_data_plt_arm::first_plt_entry, Output_data_plt_arm::plt_entry):
Move to ...
(Output_data_plt_arm_standard): ... here, new class.
(Output_data_plt_arm::do_write): Move guts of PLT filling to...
(Output_data_plt_arm_standard::do_fill_first_plt_entry): ... here ...
(Output_data_plt_arm_standard::do_fill_plt_entry): ... and here.
* x86_64.cc (Output_data_plt_x86_64::Output_data_plt_x86_64):
Take additional argument for the PLT entry size.
(Output_data_plt_x86_64::get_tlsdesc_plt_offset):
Use get_plt_entry_size method rather than plt_entry_size variable.
(Output_data_plt_x86_64::reserve_slot): Likewise.
(Output_data_plt_x86_64::do_adjust_output_section): Likewise.
(Output_data_plt_x86_64::add_entry): Likewise.
(Output_data_plt_x86_64::add_local_ifunc_entry): Likewise.
(Output_data_plt_x86_64::address_for_global): Likewise.
(Output_data_plt_x86_64::address_for_local): Likewise.
(Output_data_plt_x86_64::set_final_data_size): Likewise.
(Output_data_plt_x86_64::first_plt_entry_offset): Likewise.
Make method non-static.
(Output_data_plt_x86_64::do_get_plt_entry_size): New abstract virtual
method.
(Output_data_plt_x86_64::get_plt_entry_size): Just call that.
(Output_data_plt_x86_64::do_add_eh_frame): New abstract virtual method.
(Output_data_plt_x86_64::add_eh_frame): New method to call it.
(Output_data_plt_x86_64::do_fill_first_plt_entry): New abstract
virtual method.
(Output_data_plt_x86_64::fill_first_plt_entry): New method to call it.
(Output_data_plt_x86_64::do_fill_plt_entry): New abstract
virtual method.
(Output_data_plt_x86_64::fill_plt_entry): New method to call it.
(Output_data_plt_x86_64::do_fill_tlsdesc_entry): New abstract
virtual method.
(Output_data_plt_x86_64::fill_tlsdesc_entry): New method to call it.
(Output_data_plt_x86_64::plt_entry_size)
(Output_data_plt_x86_64::first_plt_entry)
(Output_data_plt_x86_64::plt_entry)
(Output_data_plt_x86_64::tlsdesc_plt_entry)
(Output_data_plt_x86_64::plt_eh_frame_fde_size)
(Output_data_plt_x86_64::plt_eh_frame_fde): Move to ...
(Output_data_plt_x86_64_standard): ... here, new class.
(Target_x86_64::Target_x86_64): Take optional argument for the
Target_info pointer to use.
(Target_x86_64::do_make_data_plt): New virtual method.
(Target_x86_64::make_data_plt): New method to call it.
(Target_x86_64::init_got_plt_for_update): Use that.
Call this->plt_->add_eh_frame method here.
(Output_data_plt_x86_64::init): Don't do add_eh_frame_for_plt here.
(Target_x86_64::first_plt_entry_offset): Call method on this->plt_
rather than static method.
(Target_x86_64::plt_entry_size): Likewise.
(Output_data_plt_x86_64::do_write): Use get_plt_entry_size method
rather than plt_entry_size variable. Move guts of PLT filling to...
(Output_data_plt_x86_64_standard::do_fill_first_plt_entry): ... here ...
(Output_data_plt_x86_64_standard::do_fill_plt_entry): ... and here ...
(Output_data_plt_x86_64_standard::do_fill_tlsdesc_entry): ... and here.
* i386.cc (Output_data_plt_i386::Output_data_plt_i386): Take
additional argument for the section alignment.
Don't do add_eh_frame_for_plt here.
(Output_data_plt_i386::first_plt_entry_offset): Make the method
non-static. Use get_plt_entry_size method rather than plt_entry_size
variable.
(Output_data_plt_i386::do_get_plt_entry_size): New abstract virtual
method.
(Output_data_plt_i386::get_plt_entry_size): Call it.
(Output_data_plt_i386::do_add_eh_frame): New abstract virtual method.
(Output_data_plt_i386::add_eh_frame): New method to call it.
(Output_data_plt_i386::do_fill_first_plt_entry): New abstract virtual
method.
(Output_data_plt_i386::fill_first_plt_entry): New method to call it.
(Output_data_plt_i386::do_fill_plt_entry): New abstract virtual
method.
(Output_data_plt_i386::fill_plt_entry): New method to call it.
(Output_data_plt_i386::set_final_data_size): Use get_plt_entry_size
method instead of plt_entry_size.
(Output_data_plt_i386::plt_entry_size)
(Output_data_plt_i386::plt_eh_frame_fde_size)
(Output_data_plt_i386::plt_eh_frame_fde): Move to ...
(Output_data_plt_i386_standard): ... here, new class.
(Output_data_plt_i386_exec): New class.
(Output_data_plt_i386::exec_first_plt_entry): Move to ...
(Output_data_plt_i386_exec::first_plt_entry): ... here.
(Output_data_plt_i386::exec_plt_entry): Move to ...
(Output_data_plt_i386_exec::plt_entry): ... here.
(Output_data_plt_i386_dyn): New class.
(Output_data_plt_i386::first_plt_entry): Move to ...
(Output_data_plt_i386_dyn::first_plt_entry): ... here.
(Output_data_plt_i386::dyn_plt_entry): Move to ...
(Output_data_plt_i386_dyn::plt_entry): ... here.
(Target_i386::Target_i386): Take optional argument for the Target_info
pointer to use.
(Target_i386::do_make_data_plt): New virtual method.
(Target_i386::make_data_plt): New method to call it.
(Target_i386::make_plt_section): Use that.
Call this->plt_->add_eh_frame method here.
(Output_data_plt_i386::add_entry): Use get_plt_entry_size method
rather than plt_entry_size variable.
(Output_data_plt_i386::add_local_ifunc_entry): Likewise.
(Output_data_plt_i386::address_for_local): Likewise.
(Output_data_plt_i386::do_write): Likewise.
Move guts of PLT filling to...
(Output_data_plt_i386_exec::do_fill_first_plt_entry): ... here ...
(Output_data_plt_i386_exec::do_fill_plt_entry): ... and here ...
(Output_data_plt_i386_dyn::do_fill_first_plt_entry): ... and here ...
(Output_data_plt_i386_dyn::do_fill_plt_entry): ... and here.
Change-Id: Id24b95600489835ff5e860a39c147203d4380c2b
+2012-05-02 Roland McGrath <mcgrathr@google.com>
+
+ * configure.ac (ENABLE_GOLD): Consider *-*-nacl* targets ELF.
+ * configure: Regenerate.
+
2012-04-25 Joel Brobecker <brobecker@adacore.com>
* config.sub: Update to 2012-04-18 version from official repo.
* config.guess: Update to version 2011-02-02
* config.sub: Update to version 2011-02-24
-
+
2011-03-03 Sebastian Pop <sebastian.pop@amd.com>
* configure.ac: Adjust test of with_ppl.
*-*-elf* | *-*-sysv4* | *-*-unixware* | *-*-eabi* | hppa*64*-*-hpux* \
| *-*-linux* | frv-*-uclinux* | *-*-irix5* | *-*-irix6* \
| *-*-netbsd* | *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* \
- | *-*-solaris2* | *-*-nto*)
+ | *-*-solaris2* | *-*-nto* | *-*-nacl*)
case "${target}" in
*-*-linux*aout* | *-*-linux*oldld*)
;;
### or a host dependent tool. Then put it into the appropriate list
### (library or tools, host or target), doing a dependency sort.
-# Subdirs will be configured in the order listed in build_configdirs,
+# Subdirs will be configured in the order listed in build_configdirs,
# configdirs, or target_configdirs; see the serialization section below.
-# Dependency sorting is only needed when *configuration* must be done in
-# a particular order. In all cases a dependency should be specified in
+# Dependency sorting is only needed when *configuration* must be done in
+# a particular order. In all cases a dependency should be specified in
# the Makefile, whether or not it's implicitly specified here.
# Double entries in build_configdirs, configdirs, or target_configdirs may
is_cross_compiler=no
else
is_cross_compiler=yes
-fi
+fi
# Find the build and target subdir names.
GCC_TOPLEV_SUBDIRS
noconfigdirs="$noconfigdirs zlib"
fi
-# some tools are so dependent upon X11 that if we're not building with X,
+# some tools are so dependent upon X11 that if we're not building with X,
# it's not even worth trying to configure, much less build, that tool.
case ${with_x} in
no)
skipdirs="${skipdirs} tk itcl libgui"
# We won't be able to build gdbtk without X.
- enable_gdbtk=no
+ enable_gdbtk=no
;;
*) echo "*** bad value \"${with_x}\" for -with-x flag; ignored" 1>&2 ;;
esac
*-*-elf* | *-*-sysv4* | *-*-unixware* | *-*-eabi* | hppa*64*-*-hpux* \
| *-*-linux* | frv-*-uclinux* | *-*-irix5* | *-*-irix6* \
| *-*-netbsd* | *-*-openbsd* | *-*-freebsd* | *-*-dragonfly* \
- | *-*-solaris2* | *-*-nto*)
+ | *-*-solaris2* | *-*-nto* | *-*-nacl*)
case "${target}" in
*-*-linux*aout* | *-*-linux*oldld*)
;;
# Only spaces may be used in this macro; not newlines or tabs.
unsupported_languages=
-# Remove more programs from consideration, based on the host or
+# Remove more programs from consideration, based on the host or
# target this usually means that a port of the program doesn't
# exist yet.
;;
*-*-lynxos*)
noconfigdirs="$noconfigdirs ${libgcj}"
- ;;
+ ;;
esac
# Default libgloss CPU subdirectory.
;;
*-*-lynxos*)
noconfigdirs="$noconfigdirs target-newlib target-libgloss"
- ;;
+ ;;
*-*-mingw*)
noconfigdirs="$noconfigdirs target-newlib target-libgloss"
;;
hppa*-hp-hpux*)
host_makefile_frag="config/mh-pa"
;;
- hppa*-*)
+ hppa*-*)
host_makefile_frag="config/mh-pa"
;;
*-*-darwin*)
# an apparent bug in bash 1.12 on linux.
${srcdir}/gcc/[[*]]/config-lang.in) ;;
*)
- # From the config-lang.in, get $language, $target_libs,
+ # From the config-lang.in, get $language, $target_libs,
# $lang_dirs, $boot_language, and $build_by_default
language=
target_libs=
build_configdirs_all="$build_configdirs"
build_configdirs=
for i in ${build_configdirs_all} ; do
- j=`echo $i | sed -e s/build-//g`
+ j=`echo $i | sed -e s/build-//g`
if test -f ${srcdir}/$j/configure ; then
build_configdirs="${build_configdirs} $i"
fi
target_configdirs_all="$target_configdirs"
target_configdirs=
for i in ${target_configdirs_all} ; do
- j=`echo $i | sed -e s/target-//g`
+ j=`echo $i | sed -e s/target-//g`
if test -f ${srcdir}/$j/configure ; then
target_configdirs="${target_configdirs} $i"
fi
copy_dirs=
-AC_ARG_WITH([build-sysroot],
+AC_ARG_WITH([build-sysroot],
[AS_HELP_STRING([--with-build-sysroot=SYSROOT],
[use sysroot as the system root during the build])],
[if test x"$withval" != x ; then
# This is done by determining whether or not the appropriate directory
# is available, and by checking whether or not specific configurations
# have requested that this magic not happen.
-#
-# The command line options always override the explicit settings in
+#
+# The command line options always override the explicit settings in
# configure.in, and the settings in configure.in override this magic.
#
-# If the default for a toolchain is to use GNU as and ld, and you don't
+# If the default for a toolchain is to use GNU as and ld, and you don't
# want to do that, then you should use the --without-gnu-as and
# --without-gnu-ld options for the configure script. Similarly, if
# the default is to use the included zlib and you don't want to do that,
target_makefile_frag="config/mt-gnu"
;;
*-*-aix4.[[3456789]]* | *-*-aix[[56789]].*)
- # nm and ar from AIX 4.3 and above require -X32_64 flag to all ar and nm
+ # nm and ar from AIX 4.3 and above require -X32_64 flag to all ar and nm
# commands to handle both 32-bit and 64-bit objects. These flags are
# harmless if we're using GNU nm or ar.
extra_arflags_for_target=" -X32_64"
if test -s conftest || test -s conftest.exe ; then
we_are_ok=yes
fi
-fi
+fi
case $we_are_ok in
no)
echo 1>&2 "*** The command '${CC} -o conftest ${CFLAGS} ${CPPFLAGS} ${LDFLAGS} conftest.c' failed."
# --program-suffix have been applied to it. Autoconf has already
# doubled dollar signs and backslashes in program_transform_name; we want
# the backslashes un-doubled, and then the entire thing wrapped in single
-# quotes, because this will be expanded first by make and then by the shell.
+# quotes, because this will be expanded first by make and then by the shell.
# Also, because we want to override the logic in subdir configure scripts to
# choose program_transform_name, replace any s,x,x, with s,y,y,.
sed -e "s,\\\\\\\\,\\\\,g; s,','\\\\'',g; s/s,x,x,/s,y,y,/" <<EOF_SED > conftestsed.out
AC_SUBST(CXXFLAGS)
# Target tools.
-AC_ARG_WITH([build-time-tools],
+AC_ARG_WITH([build-time-tools],
[AS_HELP_STRING([--with-build-time-tools=PATH],
[use given path to find target tools during the build])],
[case x"$withval" in
else
MAINTAINER_MODE_TRUE='#'
MAINTAINER_MODE_FALSE=
-fi
+fi
MAINT=$MAINTAINER_MODE_TRUE
AC_SUBST(MAINT)dnl
+2012-05-02 Roland McGrath <mcgrathr@google.com>
+
+ * nacl.cc: New file.
+ * nacl.h: New file.
+ * Makefile.am (CCFILES, HFILES): Add them.
+ * Makefile.in: Regenerate.
+ * i386.cc (Output_data_plt_i386_nacl): New class.
+ (Output_data_plt_i386_nacl_exec): New class.
+ (Output_data_plt_i386_nacl_dyn): New class.
+ (Target_i386_nacl): New class.
+ (Target_selector_i386_nacl): New class.
+ (target_selector_i386): Use it instead of Target_selector_i386.
+ * x86_64.cc (Output_data_plt_x86_64_nacl): New class.
+ (Target_x86_64_nacl): New class.
+ (Target_selector_x86_64_nacl): New class.
+ (target_selector_x86_64, target_selector_x32): Use it instead of
+ Target_selector_x86_64.
+ * arm.cc (Output_data_plt_arm_nacl): New class.
+ (Target_arm_nacl): New class.
+ (Target_selector_arm_nacl): New class.
+ (target_selector_arm, target_selector_armbe): Use it instead of
+ Target_selector_arm.
+
+ * target-select.cc (select_target): Take new Input_file* and off_t
+ arguments, pass them on to recognize method of selector.
+ * object.cc (make_elf_sized_object): Update caller.
+ * parameters.cc (parameters_force_valid_target): Likewise.
+ * incremental.cc (make_sized_incremental_binary): Likewise.
+ * target-select.h: Update decl.
+ (Target_selector::recognize): Take new Input_file* argument,
+ pass it on to do_recognize.
+ (Target_selector::do_recognize): Take new Input_file* argument.
+ * freebsd.h (Target_selector_freebsd::do_recognize): Likewise.
+ * powerpc.cc (Target_selector_powerpc::do_recognize): Likewise.
+ * sparc.cc (Target_selector_sparc::do_recognize): Likewise.
+ * testsuite/testfile.cc (Target_selector::do_recognize): Likewise.
+
+ * target.h (Target::Target_info): New members isolate_execinstr
+ and rosegment_gap.
+ (Target::isolate_execinstr, Target::rosegment_gap): New methods.
+ * arm.cc (Target_arm::arm_info): Update initializer.
+ * i386.cc (Target_i386::i386_info): Likewise.
+ * powerpc.cc (Target_powerpc::powerpc_info): Likewise.
+ * sparc.cc (Target_sparc::sparc_info): Likewise.
+ * x86_64.cc (Target_x86_64::x86_64_info): Likewise.
+ * testsuite/testfile.cc (Target_test::test_target_info): Likewise.
+ * layout.cc (Layout::attach_allocated_section_to_segment):
+ Take new const Target* argument. If target->isolate_execinstr(), act
+ like --rosegment.
+ (Layout::find_first_load_seg): Take new const Target* argument;
+ if target->isolate_execinstr(), reject PF_X segments.
+ (Layout::relaxation_loop_body): Update caller.
+ (Layout::set_segment_offsets): If target->isolate_execinstr(),
+ reset file offset to zero when we hit LOAD_SEG, and then do a second
+ loop over the segments before LOAD_SEG to reassign offsets after
+ addresses have been determined. Handle target->rosegment_gap().
+ (Layout::attach_section_to_segment): Take new const Target* argument;
+ pass it to attach_allocated_section_to_segment.
+ (Layout::make_output_section): Update caller.
+ (Layout::attach_sections_to_segments): Take new const Target* argument;
+ pass it to attach_section_to_segment.
+ * gold.cc (queue_middle_tasks): Update caller.
+ * layout.h (Layout): Update method decls with new arguments.
+
+ * arm.cc (Target_arm::Target_arm): Take optional argument for the
+ Target_info pointer to use.
+ (Target_arm::do_make_data_plt): New virtual method.
+ (Target_arm::make_data_plt): New method that calls it.
+ (Target_arm::make_plt_entry): Use it.
+ (Output_data_plt_arm::Output_data_plt_arm): Take additional argument
+ for the section alignment.
+ (Output_data_plt_arm::do_first_plt_entry_offset): New abstract virtual
+ method.
+ (Output_data_plt_arm::first_plt_entry_offset): Call it.
+ (Output_data_plt_arm::do_get_plt_entry_size): New abstract virtual
+ method.
+ (Output_data_plt_arm::get_plt_entry_size): Call it.
+ (Output_data_plt_arm::do_fill_plt_entry): New abstract virtual method.
+ (Output_data_plt_arm::fill_plt_entry): New method that calls it.
+ (Output_data_plt_arm::do_fill_first_plt_entry): New abstract virtual
+ method.
+ (Output_data_plt_arm::fill_first_plt_entry): New method that calls it.
+ (Output_data_plt_arm::set_final_data_size): Use get_plt_entry_size
+ method instead of sizeof(plt_entry).
+ (Output_data_plt_arm::add_entry): Likewise.
+ Use first_plt_entry_offset method instead of sizeof(first_plt_entry).
+ (Target_arm::first_plt_entry_offset): Call method on this->plt_ rather
+ than static method.
+ (Target_arm::plt_entry_size): Likewise.
+ (Output_data_plt_arm::first_plt_entry, Output_data_plt_arm::plt_entry):
+ Move to ...
+ (Output_data_plt_arm_standard): ... here, new class.
+ (Output_data_plt_arm::do_write): Move guts of PLT filling to...
+ (Output_data_plt_arm_standard::do_fill_first_plt_entry): ... here ...
+ (Output_data_plt_arm_standard::do_fill_plt_entry): ... and here.
+
+ * x86_64.cc (Output_data_plt_x86_64::Output_data_plt_x86_64):
+ Take additional argument for the PLT entry size.
+ (Output_data_plt_x86_64::get_tlsdesc_plt_offset):
+ Use get_plt_entry_size method rather than plt_entry_size variable.
+ (Output_data_plt_x86_64::reserve_slot): Likewise.
+ (Output_data_plt_x86_64::do_adjust_output_section): Likewise.
+ (Output_data_plt_x86_64::add_entry): Likewise.
+ (Output_data_plt_x86_64::add_local_ifunc_entry): Likewise.
+ (Output_data_plt_x86_64::address_for_global): Likewise.
+ (Output_data_plt_x86_64::address_for_local): Likewise.
+ (Output_data_plt_x86_64::set_final_data_size): Likewise.
+ (Output_data_plt_x86_64::first_plt_entry_offset): Likewise.
+ Make method non-static.
+ (Output_data_plt_x86_64::do_get_plt_entry_size): New abstract virtual
+ method.
+ (Output_data_plt_x86_64::get_plt_entry_size): Just call that.
+ (Output_data_plt_x86_64::do_add_eh_frame): New abstract virtual method.
+ (Output_data_plt_x86_64::add_eh_frame): New method to call it.
+ (Output_data_plt_x86_64::do_fill_first_plt_entry): New abstract
+ virtual method.
+ (Output_data_plt_x86_64::fill_first_plt_entry): New method to call it.
+ (Output_data_plt_x86_64::do_fill_plt_entry): New abstract
+ virtual method.
+ (Output_data_plt_x86_64::fill_plt_entry): New method to call it.
+ (Output_data_plt_x86_64::do_fill_tlsdesc_entry): New abstract
+ virtual method.
+ (Output_data_plt_x86_64::fill_tlsdesc_entry): New method to call it.
+ (Output_data_plt_x86_64::plt_entry_size)
+ (Output_data_plt_x86_64::first_plt_entry)
+ (Output_data_plt_x86_64::plt_entry)
+ (Output_data_plt_x86_64::tlsdesc_plt_entry)
+ (Output_data_plt_x86_64::plt_eh_frame_fde_size)
+ (Output_data_plt_x86_64::plt_eh_frame_fde): Move to ...
+ (Output_data_plt_x86_64_standard): ... here, new class.
+ (Target_x86_64::Target_x86_64): Take optional argument for the
+ Target_info pointer to use.
+ (Target_x86_64::do_make_data_plt): New virtual method.
+ (Target_x86_64::make_data_plt): New method to call it.
+ (Target_x86_64::init_got_plt_for_update): Use that.
+ Call this->plt_->add_eh_frame method here.
+ (Output_data_plt_x86_64::init): Don't do add_eh_frame_for_plt here.
+ (Target_x86_64::first_plt_entry_offset): Call method on this->plt_
+ rather than static method.
+ (Target_x86_64::plt_entry_size): Likewise.
+ (Output_data_plt_x86_64::do_write): Use get_plt_entry_size method
+ rather than plt_entry_size variable. Move guts of PLT filling to...
+ (Output_data_plt_x86_64_standard::do_fill_first_plt_entry): ... here ...
+ (Output_data_plt_x86_64_standard::do_fill_plt_entry): ... and here ...
+ (Output_data_plt_x86_64_standard::do_fill_tlsdesc_entry): ... and here.
+
+ * i386.cc (Output_data_plt_i386::Output_data_plt_i386): Take
+ additional argument for the section alignment.
+ Don't do add_eh_frame_for_plt here.
+ (Output_data_plt_i386::first_plt_entry_offset): Make the method
+ non-static. Use get_plt_entry_size method rather than plt_entry_size
+ variable.
+ (Output_data_plt_i386::do_get_plt_entry_size): New abstract virtual
+ method.
+ (Output_data_plt_i386::get_plt_entry_size): Call it.
+ (Output_data_plt_i386::do_add_eh_frame): New abstract virtual method.
+ (Output_data_plt_i386::add_eh_frame): New method to call it.
+ (Output_data_plt_i386::do_fill_first_plt_entry): New abstract virtual
+ method.
+ (Output_data_plt_i386::fill_first_plt_entry): New method to call it.
+ (Output_data_plt_i386::do_fill_plt_entry): New abstract virtual
+ method.
+ (Output_data_plt_i386::fill_plt_entry): New method to call it.
+ (Output_data_plt_i386::set_final_data_size): Use get_plt_entry_size
+ method instead of plt_entry_size.
+ (Output_data_plt_i386::plt_entry_size)
+ (Output_data_plt_i386::plt_eh_frame_fde_size)
+ (Output_data_plt_i386::plt_eh_frame_fde): Move to ...
+ (Output_data_plt_i386_standard): ... here, new class.
+ (Output_data_plt_i386_exec): New class.
+ (Output_data_plt_i386::exec_first_plt_entry): Move to ...
+ (Output_data_plt_i386_exec::first_plt_entry): ... here.
+ (Output_data_plt_i386::exec_plt_entry): Move to ...
+ (Output_data_plt_i386_exec::plt_entry): ... here.
+ (Output_data_plt_i386_dyn): New class.
+ (Output_data_plt_i386::first_plt_entry): Move to ...
+ (Output_data_plt_i386_dyn::first_plt_entry): ... here.
+ (Output_data_plt_i386::dyn_plt_entry): Move to ...
+ (Output_data_plt_i386_dyn::plt_entry): ... here.
+ (Target_i386::Target_i386): Take optional argument for the Target_info
+ pointer to use.
+ (Target_i386::do_make_data_plt): New virtual method.
+ (Target_i386::make_data_plt): New method to call it.
+ (Target_i386::make_plt_section): Use that.
+ Call this->plt_->add_eh_frame method here.
+ (Output_data_plt_i386::add_entry): Use get_plt_entry_size method
+ rather than plt_entry_size variable.
+ (Output_data_plt_i386::add_local_ifunc_entry): Likewise.
+ (Output_data_plt_i386::address_for_local): Likewise.
+ (Output_data_plt_i386::do_write): Likewise.
+ Move guts of PLT filling to...
+ (Output_data_plt_i386_exec::do_fill_first_plt_entry): ... here ...
+ (Output_data_plt_i386_exec::do_fill_plt_entry): ... and here ...
+ (Output_data_plt_i386_dyn::do_fill_first_plt_entry): ... and here ...
+ (Output_data_plt_i386_dyn::do_fill_plt_entry): ... and here.
+
2012-05-01 Cary Coutant <ccoutant@google.com>
* dwarf_reader.cc (Dwarf_die::read_attributes)
2012-03-19 Doug Kwan <dougkwan@google.com>
* arm.cc (Target_arm::do_define_standard_symbols): New method.
- (Target_arm::do_finalize_sections): Remove code which defines
+ (Target_arm::do_finalize_sections): Remove code which defines
__exidx_start and __exidx_end. Make symbol table parameter
anonymous as it is not used.
* gold.cc (queue_middle_tasks): Call target hook to define any
* output.cc: Likewise.
2011-05-31 Doug Kwan <dougkwan@google.com>
- Asier Llano
+ Asier Llano
PR gold/12826
* arm.cc (Target_arm::tag_cpu_arch_combine): Fix handling of
* arm.cc (Arm_output_section::Arm_output_section): Set SHF_LINK_ORDER
flag of a SHT_ARM_EXIDX section.
- * testsuite/Makefile.am (arm_exidx_test): New test rules.
+ * testsuite/Makefile.am (arm_exidx_test): New test rules.
* testsuite/Makefile.in: Regenerate.
* testsuite/arm_exidx_test.s: New file.
* testsuite/arm_exidx_test.sh: Same.
2011-02-02 Sriraman Tallam <tmsriram@google.com>
* icf.h (is_section_foldable_candidate): Change type of parameter
- to std::string.
+ to std::string.
* icf.cc (Icf::find_identical_sections): Change type of local variable
- section_name to be std::string.
+ section_name to be std::string.
(is_function_ctor_or_dtor): Change type of parameter to std::string.
2011-01-25 Ian Lance Taylor <iant@google.com>
and updating local symbols.
(Arm_input_section<big_endian>::init): Copy contents of original
input section.
- (Arm_input_section<big_endian>::do_write): Use saved contents of
+ (Arm_input_section<big_endian>::do_write): Use saved contents of
original input section instead of calling Object::section_contents
without locking.
(Arm_exidx_cantunwind::do_fixed_endian_write): Find out text section
(Arm_exidx_merged_section::Arm_exidx_merged_section): Add sanity check
for size. Allocate a buffer for merged EXIDX entries.
(Arm_exidx_merged_section::build_contents): New method.
- (Arm_exidx_merged_section::do_write): Move merge section contents
+ (Arm_exidx_merged_section::do_write): Move merge section contents
building code to Arm_exidx_merged_section::build_contetns. Write
out contetns in buffer instead of building it on the fly.
(Arm_relobj::make_exidx_input_section): Also pass text section size
2010-10-29 Viktor Kutuzov <vkutuzov@accesssoftek.com>
* testsuite/Makefile.am: Move gcctestdir/ld rule to
- NATIVE_OR_CROSS_LINKER.
+ NATIVE_OR_CROSS_LINKER.
* testsuite/Makefile.in: Regenerate.
2010-10-20 Doug Kwan <dougkwan@google.com>
2010-10-14 Cary Coutant <ccoutant@google.com>
* debug.h (DEBUG_INCREMENTAL): New flag.
- (debug_string_to_enum): Add DEBUG_INCREMENTAL).
- * gold.cc (queue_initial_tasks): Check parameters for incremental link
- mode.
- * incremental.cc (report_command_line): Ignore all forms of
- --incremental.
- * layout.cc (Layout::Layout): Check parameters for incremental link
- mode.
- * options.cc (General_options::parse_incremental): New function.
- (General_options::parse_no_incremental): New function.
- (General_options::parse_incremental_full): New function.
- (General_options::parse_incremental_update): New function.
- (General_options::incremental_mode_): New data member.
- (General_options::finalize): Check incremental_mode_.
- * options.h (General_options): Update help text for --incremental.
- Add --no-incremental, --incremental-full, --incremental-update.
- (General_options::Incremental_mode): New enum type.
- (General_options::incremental_mode): New function.
- (General_options::incremental_mode_): New data member.
- * parameters.cc (Parameters::incremental_mode_): New data member.
- (Parameters::set_options): Set incremental_mode_.
- (Parameters::set_incremental_full): New function.
- (Parameters::incremental): New function.
- (Parameters::incremental_update): New function.
- (set_parameters_incremental_full): New function.
- * parameters.h (Parameters::set_incremental_full): New function.
- (Parameters::incremental): New function.
- (Parameters::incremental_update): New function.
- (Parameters::incremental_mode_): New data member.
- (set_parameters_incremental_full): New function.
- * plugin.cc (Plugin_manager::add_input_file): Check parameters for
- incremental link mode.
- * reloc.cc (Sized_relobj::do_read_relocs): Likewise.
- (Sized_relobj::do_relocate_sections): Likewise.
- * testsuite/Makefile.am (incremental_test): Use --incremental-full
- option.
- * testsuite/Makefile.in: Regenerate.
- * testsuite/incremental_test.sh: Filter all forms of --incremental.
+ (debug_string_to_enum): Add DEBUG_INCREMENTAL).
+ * gold.cc (queue_initial_tasks): Check parameters for incremental link
+ mode.
+ * incremental.cc (report_command_line): Ignore all forms of
+ --incremental.
+ * layout.cc (Layout::Layout): Check parameters for incremental link
+ mode.
+ * options.cc (General_options::parse_incremental): New function.
+ (General_options::parse_no_incremental): New function.
+ (General_options::parse_incremental_full): New function.
+ (General_options::parse_incremental_update): New function.
+ (General_options::incremental_mode_): New data member.
+ (General_options::finalize): Check incremental_mode_.
+ * options.h (General_options): Update help text for --incremental.
+ Add --no-incremental, --incremental-full, --incremental-update.
+ (General_options::Incremental_mode): New enum type.
+ (General_options::incremental_mode): New function.
+ (General_options::incremental_mode_): New data member.
+ * parameters.cc (Parameters::incremental_mode_): New data member.
+ (Parameters::set_options): Set incremental_mode_.
+ (Parameters::set_incremental_full): New function.
+ (Parameters::incremental): New function.
+ (Parameters::incremental_update): New function.
+ (set_parameters_incremental_full): New function.
+ * parameters.h (Parameters::set_incremental_full): New function.
+ (Parameters::incremental): New function.
+ (Parameters::incremental_update): New function.
+ (Parameters::incremental_mode_): New data member.
+ (set_parameters_incremental_full): New function.
+ * plugin.cc (Plugin_manager::add_input_file): Check parameters for
+ incremental link mode.
+ * reloc.cc (Sized_relobj::do_read_relocs): Likewise.
+ (Sized_relobj::do_relocate_sections): Likewise.
+ * testsuite/Makefile.am (incremental_test): Use --incremental-full
+ option.
+ * testsuite/Makefile.in: Regenerate.
+ * testsuite/incremental_test.sh: Filter all forms of --incremental.
2010-10-12 Viktor Kutuzov <vkutuzov@accesssoftek.com>
section without SHF_EXECINSTR.
(Arm_output_section::fix_exidx_coverage): Skip input sections with
errors.
- (Arm_relobj::make_exidx_input_section): Add new parameter for text
+ (Arm_relobj::make_exidx_input_section): Add new parameter for text
section header. Make error messages more verbose. Check for
a non-executable section linked to an EXIDX section.
(Arm_relobj::do_read_symbols): Remove error checking, which has been
in a relocatable link.
(Target_arm::do_relax): Look for the EXIDX output section instead of
assuming that it is called .ARM.exidx.
- (Target_arm::fix_exidx_coverage): Add a new parameter for input
+ (Target_arm::fix_exidx_coverage): Add a new parameter for input
section list. Do not check for SHF_EXECINSTR section flags but
skip any input section with errors.
* output.cc (Output_section::Output_section): Initialize
to use Output_section_lookup_maps class.
(Output_section::add_relaxed_input_section): Adjst code for lookup
maps code refactoring.
- (Output_section::add_merge_input_section): Add a new parameter
+ (Output_section::add_merge_input_section): Add a new parameter
KEEPS_INPUT_SECTION. Adjust code to use Output_section_lookup_maps
class. If adding input section to a newly created merge output
section fails, remove the new merge section.
(Output_section::convert_input_sections_in_list_to_relaxed_input_sections):
Adjust code for use of the Output_section_lookup_maps class.
- (Output_section::find_merge_section): Ditto.
+ (Output_section::find_merge_section): Ditto.
(Output_section::build_lookup_maps): New method defintion.
- (Output_section::find_relaxed_input_section): Adjust code to use
+ (Output_section::find_relaxed_input_section): Adjust code to use
Output_section_lookup_maps class.
(Output_section::get_input_sections): Export merge sections. Adjust
code to use Output_section_lookup_maps class.
defintion. Declare method only.
(Output_section::Input_section::shndx): Ditto.
(Output_section::Input_section::output_merge_base): New method defintion.
- (Output_section::Input_section::u2_.pomb): New union field.
+ (Output_section::Input_section::u2_.pomb): New union field.
(Output_section::Merge_section_by_properties_map,
Output_section::Output_section_data_by_input_section_map,
Output_section::Ouptut_relaxed_input_section_by_input_section_map):
Remove types.
- (Output_section::add_merge_input_section): Add new parameter
+ (Output_section::add_merge_input_section): Add new parameter
KEEPS_INPUT_SECTIONS.
(Output_section::build_lookup_maps): New method declaration.
(Output_section::merge_section_map_,
section elements. Handle discard sections.
(Sort_output_sections::operator()): Handle NOLOAD sections.
* script-sections.h (Script_sections::Section_type): New enum type.
- (Script_sections::output_section_name): Add a new parameter for
+ (Script_sections::output_section_name): Add a new parameter for
returning script section type.
* script.cc (script_keyword_parsecodes): Add keywords COPY, DSECT,
INFO and NOLOAD.
thumb2_blx_in_range, thumb2_blx_in_range.o,
thumb2_blx_out_of_range.stdout, thumb2_blx_out_of_range,
thumb2_blx_out_of_range.o): New rules.
- (MOSTLYCLEANFILES): Add thumb_blx_in_range, thumb_blx_out_of_range,
+ (MOSTLYCLEANFILES): Add thumb_blx_in_range, thumb_blx_out_of_range,
thumb2_blx_in_range and thumb2_blx_out_of_range.
* testsuite/Makefile.in: Regenerate.
* arm_branch_in_range.sh: Add tests for THUMB BLX.
Stub_table::reloc_stubs_size_ and Stub_table::reloc_stubs_addralign_.
(Stub_table::reloc_stubs_size_, Stub_table::reloc_stubs_addralign_):
New data members.
- (Stub_table::update_data_size_and_addralign): Use
+ (Stub_table::update_data_size_and_addralign): Use
Stub_table::reloc_stubs_size_ and Stub_table::reloc_stubs_addralign_
instead of going over all reloc stubs.
- (Stub_table::finalize_stubs): Do not assign reloc stub offsets.
+ (Stub_table::finalize_stubs): Do not assign reloc stub offsets.
* stringpool.cc (Stringpool_template::Stringpool_template): Initialize
Stringpool_template::offset_ to size of Stringpool_char.
- (Stringpool_template::new_key_offset): Remove code to initialize
+ (Stringpool_template::new_key_offset): Remove code to initialize
Stringpool_template::offset_.
* stringpool.h (Stringpool_template::set_no_zero_null): Set
Stringpool_template::offset_ to zero.
when not optimizing.
* stringpool.h (Chunked_vector::Chunked_vector): Initialize data
member size_.
- (Chunked_vector::clear): Clear size_.
- (Chunked_vector::reserve): Call reserve method of all Element_vectors.
- (Chunked_vector::size): Return size_.
- (Chunked_vector::push_back): Use size_ to find insert position.
+ (Chunked_vector::clear): Clear size_.
+ (Chunked_vector::reserve): Call reserve method of all Element_vectors.
+ (Chunked_vector::size): Return size_.
+ (Chunked_vector::push_back): Use size_ to find insert position.
(Chunked_vector::size_): New data member.
(Stringpool_template::set_no_zero_null): Assert string set is empty.
(Stringpool_template::new_key_offset): New method declaration.
flags and attributes merging if an input file is a binary file.
* fileread.cc (Input_file::open): Record format of original file.
* fileread.h (Input_file::Format): New enum type.
- (Input_file::Input_file): Initialize data member format_.
+ (Input_file::Input_file): Initialize data member format_.
(Input_file::format): New method definition.
(Input_file::format_):: New data member.
(Arm_output_section::fix_exidx_coverage): Add a parameter for layout.
If user uses a script with a SECTIONS clause, issue only a warning
for a misplaced EXIDX input section. Otherwise, issue an error.
- (Arm_relobj::do_gc_process_relocs): Exit early if we are not doing
+ (Arm_relobj::do_gc_process_relocs): Exit early if we are not doing
garbage collection.
(Target_arm::got_mode_index_entry): Handle static linking.
(Target_arm::Scan::local): Ditto.
* arm.cc (Arm_relocate_functions::arm_branch_common): Fix bug in
handling of the maximum backward branch offset.
- (Arm_relocate_functions::thumb_branch_common): Ditto.
+ (Arm_relocate_functions::thumb_branch_common): Ditto.
* testsuite/Makefile.am (check_SCRIPTS): Add arm_branch_in_range.sh.
(check_DATA): Add arm_bl_in_range.stdout, arm_bl_out_of_range.stdout
thumb_bl_in_range.stdout, thumb_bl_out_of_range.stdout,
(Target_arm::optimize_tls_reloc, Target_arm::define_tls_base_symbol,
Target_arm::got_mod_index_entry, Target_arm::rel_tls_desc_section):
New methods.
- (Target_arm::Got_type): Add GOT_TYPE_TLS_NOFFSET, GOT_TYPE_OFFSET,
+ (Target_arm::Got_type): Add GOT_TYPE_TLS_NOFFSET, GOT_TYPE_OFFSET,
GOT_TYPE_TLS_PAIR and GOT_TYPE_TLS_DESC.
(Target_arm::got_mod_index_offset_,
Target_arm::tls_base_symbol_defined_): New data members.
* Makefile.am (HFILES): Add arm-reloc-property.h.
(DEFFILES): New.
- (TARGETSOURCES): Add arm-reloc-property.cc
- (ALL_TARGETOBJS): Add arm-reloc-property.$(OBJEXT)
+ (TARGETSOURCES): Add arm-reloc-property.cc
+ (ALL_TARGETOBJS): Add arm-reloc-property.$(OBJEXT)
(libgold_a_SOURCES): $(DEFFILES)
* Makefile.in: Regenerate.
* arm-reloc-property.cc: New file.
* arm.cc (set): Include.
(class Arm_exidx_fixup): Change type of last_input_section_ to const
pointer type.
- (Arm_output_section::Text_section_list): New type.
+ (Arm_output_section::Text_section_list): New type.
(Arm_output_section::append_text_sections_to_list): New method.
(Arm_output_section::fix_exidx_coverage): Ditto.
(Arm_relobj::Arm_relobj): Initialize exidx_section_map_.
- (Arm_relobj::convert_input_section_to_relaxed_section): Use
+ (Arm_relobj::convert_input_section_to_relaxed_section): Use
Relobj::set_section_offset() instead of
Sized_relobj::invalidate_section_offset().
- (Arm_relobj::section_needs_reloc_stub_scanning): Add an extra
+ (Arm_relobj::section_needs_reloc_stub_scanning): Add an extra
parameter for section headers. Ignore relocation sections for
unallocated sections and EXIDX sections.
(Target_arm::fix_exidx_coverage): New method.
(Arm_output_section::append_text_sections_to_list): New method.
(Arm_output_section::fix_exidx_coverage): Ditto.
(Arm_relobj::scan_sections_for_stubs): Adjust call to
- Arm_relobj::section_needs_reloc_stub_scanning.
+ Arm_relobj::section_needs_reloc_stub_scanning.
(Target_arm::do_relax): Fix EXIDX output section coverage in the
first pass.
(Target_arm::fix_exidx_coverage): New method.
(Output_section::add_merge_input_section): Ditto.
(Output_section::build_relaxation_map): Change to use Section_id
instead of Input_section_specifier as key type.
- (Output_section::convert_input_sections_in_list_to_relaxed_sections):
+ (Output_section::convert_input_sections_in_list_to_relaxed_sections):
Ditto.
(Output_section::convert_input_sections_to_relaxed_sections): Change
to use Const_section_id instead of Input_section_specifier as key type.
- (Output_section::find_merge_section): Ditto.
+ (Output_section::find_merge_section): Ditto.
(Output_section::find_relaxed_input_section): Ditto.
* output.h (Input_section_specifier): Remove class.
(Output_section::Output_section_data_by_input_section_map): Change
Stub_table::update_data_size_and_addralign,
Stub_table::apply_cortex_a8_workaround_to_address_range): New method
definitions.
- (Stub_table::relocate_stubs): Handle Cortex-A8 stubs.
+ (Stub_table::relocate_stubs): Handle Cortex-A8 stubs.
(Stub_table::do_write): Ditto.
(Target_arm::do_relax): Adjust code for changes in Stub_table.
(Arm_dynobj::attributes_section_data_): New data member declaration.
(Target_arm::Target_arm): Initialize attributes_section_data_. Change
initialization value of may_use_blx_ to false.
- (Target_arm::using_thumb2, Target_arm::using_thumb_only,
+ (Target_arm::using_thumb2, Target_arm::using_thumb_only,
Target_arm::may_use_arm_nop, Target_arm::may_use_thumb2_nop): Use
object attributes to compute results instead of hard-coding.
(Target_arm::do_attribute_arg_type, Target_arm::do_attributes_order,
base class initializer.
(Output_section::add_relaxed_input_section): New method declaration.
(Output_section::Input_section): Change visibility to protected.
- (Output_section::Input_section::relobj,
+ (Output_section::Input_section::relobj,
Output_section::Input_section::shndx): Handle relaxed input sections.
Output_section::input_sections) Change visibility to protected. Also
define overload to return a non-const pointer.
Output_section_data.
(Output_data_dynamic::set_final_data_size): Add DT_NULL tag only once.
(Output_symtab_xindex::do_write): Add array bound check.
- (Output_section::Input_section::print_to_mapfile): Handle
+ (Output_section::Input_section::print_to_mapfile): Handle
RELAXED_INPUT_SECTION_CODE.
(Output_section::Output_section): Initialize data member checkpoint_.
(Output_section::~Output_section): Delete checkpoint object pointed
an elfcpp:Ehdr as parameter.
* target.cc: Include dynobj.h.
(Target::do_make_elf_object_implementation): New.
- (Target::do_make_elf_object): New.
+ (Target::do_make_elf_object): New.
* target.h (Target::make_elf_object): New template declaration.
(Target::do_make_elf_object): New method declarations.
(Target::do_make_elf_object_implementation): New template declaration.
* Makefile.am (libgold_a_LIBADD): New.
(ld_new_DEPENDENCIES, ld_new_LDADD): Remove LIBOBJS
- * Makefile.in: Regenerate.
+ * Makefile.in: Regenerate.
* config.in (HAVE_DECL_MEMMEM, HAVE_DECL_STRNDUP): New.
* configure: Regenerate.
* configure.ac (AC_CHECK_DECLS): Add strndup and memmem.
dispositions.
* options.cc (General_options::parse_incremental_changed): New
function.
- (General_options::parse_incremental_unchanged): New function.
- (General_options::parse_incremental_unknown): New function.
- (General_options::General_options): Initialize new fields
+ (General_options::parse_incremental_unchanged): New function.
+ (General_options::parse_incremental_unknown): New function.
+ (General_options::General_options): Initialize new fields
incremental_disposition_ and implicit_incremental_.
- (General_options::finalize): Check for uasge of --incremental-*
+ (General_options::finalize): Check for uasge of --incremental-*
without --incremental.
2009-02-06 Chris Demetriou <cgd@google.com>
2009-01-31 Mikolaj Zalewski <mikolajz@google.com>
* script.cc (Lazy_demangler): New class.
- (Version_script_info::get_symbol_version_helper): Demangle a
+ (Version_script_info::get_symbol_version_helper): Demangle a
symbol only once.
2009-01-29 Cary Coutant <ccoutant@google.com>
layout.cc \
mapfile.cc \
merge.cc \
+ nacl.cc \
object.cc \
options.cc \
output.cc \
layout.h \
mapfile.h \
merge.h \
+ nacl.h \
object.h \
options.h \
output.h \
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/../config/depstand.m4 \
$(top_srcdir)/../config/gettext-sister.m4 \
+ $(top_srcdir)/../config/lcmessage.m4 \
$(top_srcdir)/../config/lead-dot.m4 \
$(top_srcdir)/../config/nls.m4 \
$(top_srcdir)/../config/override.m4 \
gdb-index.$(OBJEXT) gold.$(OBJEXT) gold-threads.$(OBJEXT) \
icf.$(OBJEXT) incremental.$(OBJEXT) int_encoding.$(OBJEXT) \
layout.$(OBJEXT) mapfile.$(OBJEXT) merge.$(OBJEXT) \
- object.$(OBJEXT) options.$(OBJEXT) output.$(OBJEXT) \
- parameters.$(OBJEXT) plugin.$(OBJEXT) readsyms.$(OBJEXT) \
- reduced_debug_output.$(OBJEXT) reloc.$(OBJEXT) \
- resolve.$(OBJEXT) script-sections.$(OBJEXT) script.$(OBJEXT) \
- stringpool.$(OBJEXT) symtab.$(OBJEXT) target.$(OBJEXT) \
- target-select.$(OBJEXT) timer.$(OBJEXT) version.$(OBJEXT) \
- workqueue.$(OBJEXT) workqueue-threads.$(OBJEXT)
+ nacl.$(OBJEXT) object.$(OBJEXT) options.$(OBJEXT) \
+ output.$(OBJEXT) parameters.$(OBJEXT) plugin.$(OBJEXT) \
+ readsyms.$(OBJEXT) reduced_debug_output.$(OBJEXT) \
+ reloc.$(OBJEXT) resolve.$(OBJEXT) script-sections.$(OBJEXT) \
+ script.$(OBJEXT) stringpool.$(OBJEXT) symtab.$(OBJEXT) \
+ target.$(OBJEXT) target-select.$(OBJEXT) timer.$(OBJEXT) \
+ version.$(OBJEXT) workqueue.$(OBJEXT) \
+ workqueue-threads.$(OBJEXT)
am__objects_2 =
am__objects_3 = yyscript.$(OBJEXT)
am_libgold_a_OBJECTS = $(am__objects_1) $(am__objects_2) \
layout.cc \
mapfile.cc \
merge.cc \
+ nacl.cc \
object.cc \
options.cc \
output.cc \
layout.h \
mapfile.h \
merge.h \
+ nacl.h \
object.h \
options.h \
output.h \
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mapfile.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/merge.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nacl.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/object.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/options.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/output.Po@am__quote@
#include "gc.h"
#include "attributes.h"
#include "arm-reloc-property.h"
+#include "nacl.h"
namespace
{
template<bool big_endian>
class Output_data_plt_arm;
+template<bool big_endian>
+class Output_data_plt_arm_standard;
+
template<bool big_endian>
class Stub_table;
//
// This is a very simple port of gold for ARM-EABI. It is intended for
// supporting Android only for the time being.
-//
+//
// TODOs:
// - Implement all static relocation types documented in arm-reloc.def.
// - Make PLTs more flexible for different architecture features like
enum Type
{
THUMB16_TYPE = 1,
- // THUMB16_SPECIAL_TYPE is used by sub-classes of Stub for instruction
+ // THUMB16_SPECIAL_TYPE is used by sub-classes of Stub for instruction
// templates with class-specific semantics. Currently this is used
// only by the Cortex_a8_stub class for handling condition codes in
// conditional branches.
static const Insn_template
thumb16_insn(uint32_t data)
- { return Insn_template(data, THUMB16_TYPE, elfcpp::R_ARM_NONE, 0); }
+ { return Insn_template(data, THUMB16_TYPE, elfcpp::R_ARM_NONE, 0); }
// A Thumb conditional branch, in which the proper condition is inserted
// when we build the stub.
static const Insn_template
thumb16_bcond_insn(uint32_t data)
- { return Insn_template(data, THUMB16_SPECIAL_TYPE, elfcpp::R_ARM_NONE, 1); }
+ { return Insn_template(data, THUMB16_SPECIAL_TYPE, elfcpp::R_ARM_NONE, 1); }
static const Insn_template
thumb32_insn(uint32_t data)
- { return Insn_template(data, THUMB32_TYPE, elfcpp::R_ARM_NONE, 0); }
+ { return Insn_template(data, THUMB32_TYPE, elfcpp::R_ARM_NONE, 0); }
static const Insn_template
thumb32_b_insn(uint32_t data, int reloc_addend)
{
return Insn_template(data, THUMB32_TYPE, elfcpp::R_ARM_THM_JUMP24,
reloc_addend);
- }
+ }
static const Insn_template
arm_insn(uint32_t data)
static const Insn_template
data_word(unsigned data, unsigned int r_type, int reloc_addend)
- { return Insn_template(data, DATA_TYPE, r_type, reloc_addend); }
+ { return Insn_template(data, DATA_TYPE, r_type, reloc_addend); }
// Accessors. This class is used for read-only objects so no modifiers
// are provided.
arm_stub_cortex_a8_first = arm_stub_a8_veneer_b_cond,
// Last Cortex-A8 stub type.
arm_stub_cortex_a8_last = arm_stub_a8_veneer_blx,
-
+
// Last stub type.
arm_stub_type_last = arm_stub_v4_veneer_bx
} Stub_type;
unsigned
alignment() const
{ return this->alignment_; }
-
+
// Return whether entry point is in thumb mode.
bool
entry_in_thumb_mode() const
// as possible.
Stub_template(const Stub_template&);
Stub_template& operator=(const Stub_template&);
-
+
// Stub type.
Stub_type type_;
// Points to an array of Insn_templates.
bool entry_in_thumb_mode_;
// A table of reloc instruction indices and offsets. We can find these by
// looking at the instruction templates but we pre-compute and then stash
- // them here for speed.
+ // them here for speed.
std::vector<Reloc> relocs_;
};
void
set_offset(section_offset_type offset)
{ this->offset_ = offset; }
-
+
// Return the relocation target address of the i-th relocation in the
// stub. This must be defined in a child class.
Arm_address
else
this->do_fixed_endian_write<false>(view, view_size);
}
-
+
// This must be overridden if a child class uses the THUMB16_SPECIAL_TYPE
// instruction template.
virtual uint16_t
// Whether this equals to another key k.
bool
- eq(const Key& k) const
+ eq(const Key& k) const
{
return ((this->stub_type_ == k.stub_type_)
&& (this->r_sym_ == k.r_sym_)
unsigned int r_sym_;
// If r_sym_ is an invalid index, this points to a global symbol.
// Otherwise, it points to a relobj. We used the unsized and target
- // independent Symbol and Relobj classes instead of Sized_symbol<32> and
+ // independent Symbol and Relobj classes instead of Sized_symbol<32> and
// Arm_relobj, in order to avoid making the stub class a template
// as most of the stub machinery is endianness-neutral. However, it
// may require a bit of casting done by users of this class.
// Cortex-A8 stub class. We need a Cortex-A8 stub to redirect any 32-bit
// THUMB branch that meets the following conditions:
-//
+//
// 1. The branch straddles across a page boundary. i.e. lower 12-bit of
// branch address is 0xffe.
// 2. The branch target address is in the same page as the first word of the
{
if (this->stub_template()->type() == arm_stub_a8_veneer_b_cond)
{
- // The conditional branch veneer has two relocations.
- gold_assert(i < 2);
+ // The conditional branch veneer has two relocations.
+ gold_assert(i < 2);
return i == 0 ? this->source_address_ + 4 : this->destination_address_;
}
else
{
- // All other Cortex-A8 stubs have only one relocation.
- gold_assert(i == 0);
- return this->destination_address_;
+ // All other Cortex-A8 stubs have only one relocation.
+ gold_assert(i == 0);
+ return this->destination_address_;
}
}
private:
// Constructor and destructor are protected since we only return a single
// instance created in Stub_factory::get_instance().
-
+
Stub_factory();
// A Stub_factory may not be copied since it is a singleton.
Stub_factory(const Stub_factory&);
Stub_factory& operator=(Stub_factory&);
-
+
// Stub templates. These are initialized in the constructor.
const Stub_template* stub_templates_[arm_stub_type_last+1];
};
// needing the Cortex-A8 workaround.
void
finalize_stubs();
-
+
// Apply Cortex-A8 workaround to an address range.
void
apply_cortex_a8_workaround_to_address_range(Target_arm<big_endian>*,
// Write out section contents.
void
do_write(Output_file*);
-
+
// Return the required alignment.
uint64_t
do_addralign() const
void
set_final_data_size()
{ this->set_data_size(this->current_data_size()); }
-
+
private:
// Relocate one stub.
void
template<bool big_endian>
void inline
do_fixed_endian_write(Output_file*);
-
+
// The object containing the section pointed by this.
Relobj* relobj_;
// The section index of the section pointed by this.
// During EXIDX coverage fix-up, we compact an EXIDX section. The
// Offset map is used to map input section offset within the EXIDX section
-// to the output offset from the start of this EXIDX section.
+// to the output offset from the start of this EXIDX section.
typedef std::map<section_offset_type, section_offset_type>
Arm_exidx_section_offset_map;
const Arm_exidx_input_section& exidx_input_section_;
// Section offset map.
const Arm_exidx_section_offset_map& section_offset_map_;
- // Merged section contents. We need to keep build the merged section
+ // Merged section contents. We need to keep build the merged section
// and save it here to avoid accessing the original EXIDX section when
// we cannot lock the sections' object.
unsigned char* section_contents_;
// Initialize.
void
init();
-
+
// Whether this is a stub table owner.
bool
is_stub_table_owner() const
bool
do_output_offset(const Relobj* object, unsigned int shndx,
section_offset_type offset,
- section_offset_type* poutput) const
+ section_offset_type* poutput) const
{
if ((object == this->relobj())
&& (shndx == this->shndx())
const unsigned char* section_contents,
section_size_type section_size,
Arm_exidx_section_offset_map** psection_offset_map);
-
+
// Append an EXIDX_CANTUNWIND entry pointing at the end of the last
// input section, if there is not one already.
void
~Arm_output_section()
{ }
-
+
// Group input sections for stub generation.
void
group_sections(section_size_type, bool, Target_arm<big_endian>*, const Task*);
~Arm_exidx_input_section()
{ }
-
+
// Accessors: This is a read-only class.
// Return the object containing this EXIDX input section.
static const Arm_address invalid_address = static_cast<Arm_address>(-1);
Arm_relobj(const std::string& name, Input_file* input_file, off_t offset,
- const typename elfcpp::Ehdr<32, big_endian>& ehdr)
+ const typename elfcpp::Ehdr<32, big_endian>& ehdr)
: Sized_relobj_file<32, big_endian>(name, input_file, offset, ehdr),
stub_tables_(), local_symbol_is_thumb_function_(),
attributes_section_data_(NULL), mapping_symbols_info_(),
~Arm_relobj()
{ delete this->attributes_section_data_; }
-
+
// Return the stub table of the SHNDX-th section if there is one.
Stub_table<big_endian>*
stub_table(unsigned int shndx) const
gold_assert(r_sym < this->local_symbol_is_thumb_function_.size());
return this->local_symbol_is_thumb_function_[r_sym];
}
-
+
// Scan all relocation sections for stub generation.
void
scan_sections_for_stubs(Target_arm<big_endian>*, const Symbol_table*,
|| (p1.first == p2.first && p1.second < p2.second));
}
};
-
+
// We only care about the first character of a mapping symbol, so
// we only store that instead of the whole symbol name.
typedef std::map<Mapping_symbol_position, char,
// Whether a section contains any Cortex-A8 workaround.
bool
section_has_cortex_a8_workaround(unsigned int shndx) const
- {
+ {
return (this->section_has_cortex_a8_workaround_ != NULL
&& (*this->section_has_cortex_a8_workaround_)[shndx]);
}
-
+
// Mark a section that has Cortex-A8 workaround.
void
mark_section_for_cortex_a8_workaround(unsigned int shndx)
void
set_output_local_symbol_count_needs_update()
{ this->output_local_symbol_count_needs_update_ = true; }
-
+
// Update output local symbol count at the end of relaxation.
void
update_output_local_symbol_count();
bool
merge_flags_and_attributes() const
{ return this->merge_flags_and_attributes_; }
-
+
// Export list of EXIDX section indices.
void
get_exidx_shndx_list(std::vector<unsigned int>* list) const
if (p->second->shndx() == p->first)
list->push_back(p->first);
}
- // Sort list to make result independent of implementation of map.
+ // Sort list to make result independent of implementation of map.
std::sort(list->begin(), list->end());
}
// Count the local symbols.
void
do_count_local_symbols(Stringpool_template<char>*,
- Stringpool_template<char>*);
+ Stringpool_template<char>*);
void
do_relocate_sections(
: Sized_dynobj<32, big_endian>(name, input_file, offset, ehdr),
processor_specific_flags_(0), attributes_section_data_(NULL)
{ }
-
+
~Arm_dynobj()
{ delete this->attributes_section_data_; }
{ }
// Accessors: This is a read-only class.
-
+
// Return the relocation stub associated with this relocation if there is
// one.
const Reloc_stub*
reloc_stub() const
- { return this->reloc_stub_; }
-
+ { return this->reloc_stub_; }
+
// Return the relocation type.
unsigned int
r_type() const
case elfcpp::R_ARM_TARGET2:
gold_unreachable();
// Relocations that write full 32 bits and
- // have alignment of 1.
+ // have alignment of 1.
case elfcpp::R_ARM_ABS32:
case elfcpp::R_ARM_REL32:
case elfcpp::R_ARM_SBREL32:
// When were are relocating a stub, we pass this as the relocation number.
static const size_t fake_relnum_for_stubs = static_cast<size_t>(-1);
- Target_arm()
- : Sized_target<32, big_endian>(&arm_info),
+ Target_arm(const Target::Target_info* info = &arm_info)
+ : Sized_target<32, big_endian>(info),
got_(NULL), plt_(NULL), got_plt_(NULL), rel_dyn_(NULL),
- copy_relocs_(elfcpp::R_ARM_COPY), dynbss_(NULL),
+ copy_relocs_(elfcpp::R_ARM_COPY), dynbss_(NULL),
got_mod_index_offset_(-1U), tls_base_symbol_defined_(false),
stub_tables_(), stub_factory_(Stub_factory::get_instance()),
should_force_pic_veneer_(false),
void
set_should_force_pic_veneer(bool value)
{ this->should_force_pic_veneer_ = value; }
-
+
// Whether we use THUMB-2 instructions.
bool
using_thumb2() const
return (arch != elfcpp::TAG_CPU_ARCH_PRE_V4
&& arch != elfcpp::TAG_CPU_ARCH_V4);
}
-
+
// Whether we have v5T interworking instructions available.
bool
may_use_v5t_interworking() const
&& arch != elfcpp::TAG_CPU_ARCH_V4
&& arch != elfcpp::TAG_CPU_ARCH_V4T);
}
-
- // Process the relocations to determine unreferenced sections for
+
+ // Process the relocations to determine unreferenced sections for
// garbage collection.
void
gc_process_relocs(Symbol_table* symtab,
view_address,
section_size_type view_size,
unsigned char* preloc_out);
-
+
// Return whether SYM is defined by the ABI.
bool
do_is_defined_by_abi(const Symbol* sym) const
//
// Methods to support stub-generations.
//
-
+
// Return the stub factory
const Stub_factory&
stub_factory() const
bool, const unsigned char*, Arm_address,
section_size_type);
- // Relocate a stub.
+ // Relocate a stub.
void
relocate_stub(Stub*, const Relocate_info<32, big_endian>*,
Output_section*, unsigned char*, Arm_address,
section_size_type);
-
+
// Get the default ARM target.
static Target_arm<big_endian>*
default_target()
unsigned char*, Arm_address);
protected:
+ // Make the PLT-generator object.
+ Output_data_plt_arm<big_endian>*
+ make_data_plt(Layout* layout, Output_data_space* got_plt)
+ { return this->do_make_data_plt(layout, got_plt); }
+
// Make an ELF object.
Object*
do_make_elf_object(const std::string&, Input_file*, off_t,
&& !is_prefix_of(".ARM.extab", section_name)
&& Target::do_section_may_have_icf_unsafe_pointers(section_name));
}
-
+
virtual void
do_define_standard_symbols(Symbol_table*, Layout*);
+ virtual Output_data_plt_arm<big_endian>*
+ do_make_data_plt(Layout* layout, Output_data_space* got_plt)
+ {
+ return new Output_data_plt_arm_standard<big_endian>(layout, got_plt);
+ }
+
private:
// The class which scans relocations.
class Scan
inline bool
local_reloc_may_be_function_pointer(Symbol_table* , Layout* , Target_arm* ,
- Sized_relobj_file<32, big_endian>* ,
- unsigned int ,
- Output_section* ,
- const elfcpp::Rel<32, big_endian>& ,
+ Sized_relobj_file<32, big_endian>* ,
+ unsigned int ,
+ Output_section* ,
+ const elfcpp::Rel<32, big_endian>& ,
unsigned int ,
- const elfcpp::Sym<32, big_endian>&);
+ const elfcpp::Sym<32, big_endian>&);
inline bool
global_reloc_may_be_function_pointer(Symbol_table* , Layout* , Target_arm* ,
- Sized_relobj_file<32, big_endian>* ,
- unsigned int ,
- Output_section* ,
- const elfcpp::Rel<32, big_endian>& ,
+ Sized_relobj_file<32, big_endian>* ,
+ unsigned int ,
+ Output_section* ,
+ const elfcpp::Rel<32, big_endian>& ,
unsigned int , Symbol*);
private:
// Do a TLS relocation.
inline typename Arm_relocate_functions<big_endian>::Status
relocate_tls(const Relocate_info<32, big_endian>*, Target_arm<big_endian>*,
- size_t, const elfcpp::Rel<32, big_endian>&, unsigned int,
+ size_t, const elfcpp::Rel<32, big_endian>&, unsigned int,
const Sized_symbol<32>*, const Symbol_value<32>*,
unsigned char*, elfcpp::Elf_types<32>::Elf_Addr,
section_size_type);
Arm_input_section<big_endian>*,
Section_id_hash>
Arm_input_section_map;
-
+
// Map output addresses to relocs for Cortex-A8 erratum.
typedef Unordered_map<Arm_address, const Cortex_a8_reloc*>
Cortex_a8_relocs_info;
0x8000, // default_text_segment_address
0x1000, // abi_pagesize (overridable by -z max-page-size)
0x1000, // common_pagesize (overridable by -z common-page-size)
+ false, // isolate_execinstr
+ 0, // rosegment_gap
elfcpp::SHN_UNDEF, // small_common_shndx
elfcpp::SHN_UNDEF, // large_common_shndx
0, // small_common_section_flags
// Encoding of imm16 argument for movt and movw ARM instructions
// from ARM ARM:
- //
+ //
// imm16 := imm4 | imm12
//
- // f e d c b a 9 8 7 6 5 4 3 2 1 0 f e d c b a 9 8 7 6 5 4 3 2 1 0
+ // f e d c b a 9 8 7 6 5 4 3 2 1 0 f e d c b a 9 8 7 6 5 4 3 2 1 0
// +-------+---------------+-------+-------+-----------------------+
// | | |imm4 | |imm12 |
// +-------+---------------+-------+-------+-----------------------+
// Encoding of imm16 argument for movt and movw Thumb2 instructions
// from ARM ARM:
- //
+ //
// imm16 := imm4 | i | imm3 | imm8
//
- // f e d c b a 9 8 7 6 5 4 3 2 1 0 f e d c b a 9 8 7 6 5 4 3 2 1 0
+ // f e d c b a 9 8 7 6 5 4 3 2 1 0 f e d c b a 9 8 7 6 5 4 3 2 1 0
// +---------+-+-----------+-------++-+-----+-------+---------------+
// | |i| |imm4 || |imm3 | |imm8 |
// +---------+-+-----------+-------++-+-----+-------+---------------+
uint32_t s = offset < 0 ? 1 : 0;
uint32_t bits = static_cast<uint32_t>(offset);
return ((lower_insn & ~0x2fffU)
- | ((((bits >> 23) & 1) ^ !s) << 13)
- | ((((bits >> 22) & 1) ^ !s) << 11)
- | ((bits >> 1) & 0x7ffU));
+ | ((((bits >> 23) & 1) ^ !s) << 13)
+ | ((((bits >> 22) & 1) ^ !s) << 11)
+ | ((bits >> 1) & 0x7ffU));
}
// Return the branch offset of a 32-bit THUMB conditional branch.
int32_t addend = Bits<8>::sign_extend32((val & 0x00ff) << 1);
int32_t x = (psymval->value(object, addend) - address);
elfcpp::Swap<16, big_endian>::writeval(wv, ((val & 0xff00)
- | ((x & 0x01fe) >> 1)));
+ | ((x & 0x01fe) >> 1)));
// We do a 9-bit overflow check because x is right-shifted by 1 bit.
return (Bits<9>::has_overflow32(x)
? This::STATUS_OVERFLOW
int32_t addend = Bits<11>::sign_extend32((val & 0x07ff) << 1);
int32_t x = (psymval->value(object, addend) - address);
elfcpp::Swap<16, big_endian>::writeval(wv, ((val & 0xf800)
- | ((x & 0x0ffe) >> 1)));
+ | ((x & 0x0ffe) >> 1)));
// We do a 12-bit overflow check because x is right-shifted by 1 bit.
return (Bits<12>::has_overflow32(x)
? This::STATUS_OVERFLOW
elfcpp::Swap<16, big_endian>::writeval(wv, val >> 16);
elfcpp::Swap<16, big_endian>::writeval(wv + 1, val & 0xffff);
return ((check_overflow && Bits<16>::has_overflow32(x))
- ? This::STATUS_OVERFLOW
+ ? This::STATUS_OVERFLOW
: This::STATUS_OKAY);
}
elfcpp::Swap<16, big_endian>::writeval(wv, insn >> 16);
elfcpp::Swap<16, big_endian>::writeval(wv + 1, insn & 0xffff);
return ((val > 0xfff) ?
- This::STATUS_OVERFLOW : This::STATUS_OKAY);
+ This::STATUS_OVERFLOW : This::STATUS_OKAY);
}
// R_ARM_THM_PC8: S + A - Pa (Thumb)
elfcpp::Swap<16, big_endian>::writeval(wv, insn >> 16);
elfcpp::Swap<16, big_endian>::writeval(wv + 1, insn & 0xffff);
return ((val > 0xfff) ?
- This::STATUS_OVERFLOW : This::STATUS_OKAY);
+ This::STATUS_OVERFLOW : This::STATUS_OKAY);
}
// R_ARM_V4BX
typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype;
Valtype* wv = reinterpret_cast<Valtype*>(view);
Valtype val = elfcpp::Swap<32, big_endian>::readval(wv);
-
+
bool insn_is_b = (((val >> 28) & 0xf) <= 0xe)
- && ((val & 0x0f000000UL) == 0x0a000000UL);
+ && ((val & 0x0f000000UL) == 0x0a000000UL);
bool insn_is_uncond_bl = (val & 0xff000000UL) == 0xeb000000UL;
bool insn_is_cond_bl = (((val >> 28) & 0xf) < 0xe)
&& ((val & 0x0f000000UL) == 0x0b000000UL);
elfcpp::Swap<32, big_endian>::writeval(wv, val);
return This::STATUS_OKAY;
}
-
+
Valtype addend = Bits<26>::sign_extend32(val << 2);
Valtype branch_target = psymval->value(object, addend);
int32_t branch_offset = branch_target - address;
// into account.
bool is_bl_insn = (lower_insn & 0x1000U) == 0x1000U;
bool is_blx_insn = (lower_insn & 0x1000U) == 0x0000U;
-
+
// Check that the instruction is valid.
if (r_type == elfcpp::R_ARM_THM_CALL)
{
gold_warning(_("%s: Thumb BLX instruction targets "
"thumb function '%s'."),
object->name().c_str(),
- (gsym ? gsym->name() : "(local)"));
+ (gsym ? gsym->name() : "(local)"));
// Convert BLX to BL.
lower_insn |= 0x1000U;
}
}
return This::STATUS_OKAY;
}
-
+
int32_t addend = This::thumb32_branch_offset(upper_insn, lower_insn);
Arm_address branch_target = psymval->value(object, addend);
gold_assert(stub != NULL);
thumb_bit = stub->stub_template()->entry_in_thumb_mode() ? 1 : 0;
branch_target = stub_table->address() + stub->offset() + addend;
- if (thumb_bit == 0 && may_use_blx)
+ if (thumb_bit == 0 && may_use_blx)
branch_target = Bits<32>::bit_select32(branch_target, address, 0x2);
branch_offset = branch_target - address;
}
break;
case Insn_template::THUMB32_TYPE:
- if (insns[i].r_type() != elfcpp::R_ARM_NONE)
+ if (insns[i].r_type() != elfcpp::R_ARM_NONE)
this->relocs_.push_back(Reloc(i, offset));
if (i == 0)
this->entry_in_thumb_mode_ = true;
- break;
+ break;
case Insn_template::ARM_TYPE:
// Handle cases where the target is encoded within the
default:
gold_unreachable();
}
- offset += insn_size;
+ offset += insn_size;
}
this->size_ = offset;
}
elfcpp::Swap<16, big_endian>::writeval(pov, hi);
elfcpp::Swap<16, big_endian>::writeval(pov + 2, lo);
}
- break;
+ break;
case Insn_template::ARM_TYPE:
case Insn_template::DATA_TYPE:
elfcpp::Swap<32, big_endian>::writeval(pov, insns[i].data());
pov += insns[i].size();
}
gold_assert(static_cast<section_size_type>(pov - view) == view_size);
-}
+}
// Reloc_stub::Key methods.
if ((r_type == elfcpp::R_ARM_THM_CALL) && may_use_blx && !target_is_thumb)
destination = Bits<32>::bit_select32(destination, location, 0x2);
branch_offset = static_cast<int64_t>(destination) - location;
-
+
// Handle cases where:
// - this call goes too far (different Thumb/Thumb2 max
// distance)
else
{
// Thumb to arm.
-
+
// FIXME: We should check that the input section is from an
// object that has interwork enabled.
{
// The instruction template sequences are declared as static
// objects and initialized first time the constructor runs.
-
+
// Arm/Thumb -> Arm/Thumb long branch stub. On V5T and above, use blx
// to reach the stub if necessary.
static const Insn_template elf32_arm_stub_long_branch_any_any[] =
{
Insn_template::arm_insn(0xe51ff004), // ldr pc, [pc, #-4]
Insn_template::data_word(0, elfcpp::R_ARM_ABS32, 0),
- // dcd R_ARM_ABS32(X)
+ // dcd R_ARM_ABS32(X)
};
-
+
// V4T Arm -> Thumb long branch stub. Used on V4T where blx is not
// available.
static const Insn_template elf32_arm_stub_long_branch_v4t_arm_thumb[] =
Insn_template::arm_insn(0xe59fc000), // ldr ip, [pc, #0]
Insn_template::arm_insn(0xe12fff1c), // bx ip
Insn_template::data_word(0, elfcpp::R_ARM_ABS32, 0),
- // dcd R_ARM_ABS32(X)
+ // dcd R_ARM_ABS32(X)
};
-
+
// Thumb -> Thumb long branch stub. Used on M-profile architectures.
static const Insn_template elf32_arm_stub_long_branch_thumb_only[] =
{
Insn_template::thumb16_insn(0x4760), // bx ip
Insn_template::thumb16_insn(0xbf00), // nop
Insn_template::data_word(0, elfcpp::R_ARM_ABS32, 0),
- // dcd R_ARM_ABS32(X)
+ // dcd R_ARM_ABS32(X)
};
-
+
// V4T Thumb -> Thumb long branch stub. Using the stack is not
// allowed.
static const Insn_template elf32_arm_stub_long_branch_v4t_thumb_thumb[] =
Insn_template::arm_insn(0xe59fc000), // ldr ip, [pc, #0]
Insn_template::arm_insn(0xe12fff1c), // bx ip
Insn_template::data_word(0, elfcpp::R_ARM_ABS32, 0),
- // dcd R_ARM_ABS32(X)
+ // dcd R_ARM_ABS32(X)
};
-
+
// V4T Thumb -> ARM long branch stub. Used on V4T where blx is not
// available.
static const Insn_template elf32_arm_stub_long_branch_v4t_thumb_arm[] =
Insn_template::thumb16_insn(0x46c0), // nop
Insn_template::arm_insn(0xe51ff004), // ldr pc, [pc, #-4]
Insn_template::data_word(0, elfcpp::R_ARM_ABS32, 0),
- // dcd R_ARM_ABS32(X)
+ // dcd R_ARM_ABS32(X)
};
-
+
// V4T Thumb -> ARM short branch stub. Shorter variant of the above
// one, when the destination is close enough.
static const Insn_template elf32_arm_stub_short_branch_v4t_thumb_arm[] =
Insn_template::thumb16_insn(0x46c0), // nop
Insn_template::arm_rel_insn(0xea000000, -8), // b (X-8)
};
-
+
// ARM/Thumb -> ARM long branch stub, PIC. On V5T and above, use
// blx to reach the stub if necessary.
static const Insn_template elf32_arm_stub_long_branch_any_arm_pic[] =
Insn_template::arm_insn(0xe59fc000), // ldr r12, [pc]
Insn_template::arm_insn(0xe08ff00c), // add pc, pc, ip
Insn_template::data_word(0, elfcpp::R_ARM_REL32, -4),
- // dcd R_ARM_REL32(X-4)
+ // dcd R_ARM_REL32(X-4)
};
-
+
// ARM/Thumb -> Thumb long branch stub, PIC. On V5T and above, use
// blx to reach the stub if necessary. We can not add into pc;
// it is not guaranteed to mode switch (different in ARMv6 and
Insn_template::arm_insn(0xe08fc00c), // add ip, pc, ip
Insn_template::arm_insn(0xe12fff1c), // bx ip
Insn_template::data_word(0, elfcpp::R_ARM_REL32, 0),
- // dcd R_ARM_REL32(X)
+ // dcd R_ARM_REL32(X)
};
-
+
// V4T ARM -> ARM long branch stub, PIC.
static const Insn_template elf32_arm_stub_long_branch_v4t_arm_thumb_pic[] =
{
Insn_template::arm_insn(0xe08fc00c), // add ip, pc, ip
Insn_template::arm_insn(0xe12fff1c), // bx ip
Insn_template::data_word(0, elfcpp::R_ARM_REL32, 0),
- // dcd R_ARM_REL32(X)
+ // dcd R_ARM_REL32(X)
};
-
+
// V4T Thumb -> ARM long branch stub, PIC.
static const Insn_template elf32_arm_stub_long_branch_v4t_thumb_arm_pic[] =
{
Insn_template::arm_insn(0xe59fc000), // ldr ip, [pc, #0]
Insn_template::arm_insn(0xe08cf00f), // add pc, ip, pc
Insn_template::data_word(0, elfcpp::R_ARM_REL32, -4),
- // dcd R_ARM_REL32(X)
+ // dcd R_ARM_REL32(X)
};
-
+
// Thumb -> Thumb long branch stub, PIC. Used on M-profile
// architectures.
static const Insn_template elf32_arm_stub_long_branch_thumb_only_pic[] =
Insn_template::thumb16_insn(0xbc01), // pop {r0}
Insn_template::thumb16_insn(0x4760), // bx ip
Insn_template::data_word(0, elfcpp::R_ARM_REL32, 4),
- // dcd R_ARM_REL32(X)
+ // dcd R_ARM_REL32(X)
};
-
+
// V4T Thumb -> Thumb long branch stub, PIC. Using the stack is not
// allowed.
static const Insn_template elf32_arm_stub_long_branch_v4t_thumb_thumb_pic[] =
Insn_template::arm_insn(0xe08fc00c), // add ip, pc, ip
Insn_template::arm_insn(0xe12fff1c), // bx ip
Insn_template::data_word(0, elfcpp::R_ARM_REL32, 0),
- // dcd R_ARM_REL32(X)
+ // dcd R_ARM_REL32(X)
};
-
+
// Cortex-A8 erratum-workaround stubs.
-
+
// Stub used for conditional branches (which may be beyond +/-1MB away,
// so we can't use a conditional branch to reach this stub).
-
+
// original code:
//
// b<cond> X
Insn_template::thumb16_bcond_insn(0xd001), // b<cond>.n true
Insn_template::thumb32_b_insn(0xf000b800, -4), // b.w after
Insn_template::thumb32_b_insn(0xf000b800, -4) // true:
- // b.w X
+ // b.w X
};
-
+
// Stub used for b.w and bl.w instructions.
-
+
static const Insn_template elf32_arm_stub_a8_veneer_b[] =
{
Insn_template::thumb32_b_insn(0xf000b800, -4) // b.w dest
};
-
+
static const Insn_template elf32_arm_stub_a8_veneer_bl[] =
{
Insn_template::thumb32_b_insn(0xf000b800, -4) // b.w dest
};
-
+
// Stub used for Thumb-2 blx.w instructions. We modified the original blx.w
// instruction (which switches to ARM mode) to point to this stub. Jump to
// the real destination using an ARM-mode branch.
// Update prev_data_size_ and prev_addralign_. These will be used
// as the current data size and address alignment for the next pass.
bool changed = size != this->prev_data_size_;
- this->prev_data_size_ = size;
+ this->prev_data_size_ = size;
if (addralign != this->prev_addralign_)
changed = true;
// We have to write out the original section content.
gold_assert(this->original_contents_ != NULL);
of->write(this->offset(), this->original_contents_,
- this->original_size_);
+ this->original_size_);
// If this owns a stub table and it is not empty, write it.
if (this->is_stub_table_owner() && !this->stub_table_->empty())
off_t offset = this->offset();
const section_size_type oview_size = 8;
unsigned char* const oview = of->get_output_view(offset, oview_size);
-
+
typedef typename elfcpp::Swap_unaligned<32, big_endian>::Valtype Valtype;
Output_section* os = this->relobj_->output_section(this->shndx_);
{
section_start = os->address() + output_offset;
const Arm_exidx_input_section* exidx_input_section =
- arm_relobj->exidx_input_section_by_link(this->shndx_);
+ arm_relobj->exidx_input_section_by_link(this->shndx_);
gold_assert(exidx_input_section != NULL);
section_size =
convert_to_section_size_type(exidx_input_section->text_size());
section_offset_type out_max =
convert_types<section_offset_type>(this->data_size());
for (Arm_exidx_section_offset_map::const_iterator p =
- this->section_offset_map_.begin();
+ this->section_offset_map_.begin();
p != this->section_offset_map_.end();
++p)
{
// Offset is discarded owing to EXIDX entry merging.
*poutput = -1;
}
-
+
return true;
}
off_t offset = this->offset();
const section_size_type oview_size = this->data_size();
unsigned char* const oview = of->get_output_view(offset, oview_size);
-
+
Output_section* os = this->relobj()->output_section(this->shndx());
gold_assert(os != NULL);
this->last_unwind_type_ = UT_NONE;
return 0;
}
-
+
uint32_t deleted_bytes = 0;
bool prev_delete_entry = false;
gold_assert(this->section_offset_map_ == NULL);
prev_delete_entry = delete_entry;
}
-
+
// If section offset map is not NULL, make an entry for the end of
// section.
if (this->section_offset_map_ != NULL)
*psection_offset_map = this->section_offset_map_;
this->section_offset_map_ = NULL;
this->last_input_section_ = exidx_input_section;
-
+
// Set the first output text section so that we can link the EXIDX output
// section to it. Ignore any EXIDX input section that is completely merged.
if (this->first_output_text_section_ == NULL
// We use a different kind of relaxed section in an EXIDX section.
// The static casting from Output_relaxed_input_section to
// Arm_input_section is invalid in an EXIDX section. We are okay
- // because we should not be calling this for an EXIDX section.
+ // because we should not be calling this for an EXIDX section.
gold_assert(this->type() != elfcpp::SHT_ARM_EXIDX);
// Currently we convert ordinary input sections into relaxed sections only
// at this point but we may want to support creating relaxed input section
// very early. So we check here to see if owner is already a relaxed
// section.
-
+
Arm_input_section<big_endian>* arm_input_section;
if (owner->is_relaxed_input_section())
{
target->new_stub_table(arm_input_section);
arm_input_section->set_stub_table(stub_table);
-
+
Input_section_list::const_iterator p = begin;
Input_section_list::const_iterator prev_p;
// size is just below GROUP_SIZE. The last input section will be converted
// into a stub table. If STUB_ALWAYS_AFTER_BRANCH is false, we also add
// input section after the stub table, effectively double the group size.
-//
+//
// This is similar to the group_sections() function in elf32-arm.c but is
// implemented differently.
section_size_type section_begin_offset =
align_address(off, p->addralign());
section_size_type section_end_offset =
- section_begin_offset + p->data_size();
-
+ section_begin_offset + p->data_size();
+
// Check to see if we should group the previously seen sections.
switch (state)
{
if (section_end_offset - group_begin_offset >= group_size)
{
if (stubs_always_after_branch)
- {
+ {
gold_assert(group_end != this->input_sections().end());
this->create_stub_group(group_begin, group_end, group_end,
target, &new_relaxed_sections,
default:
gold_unreachable();
- }
+ }
// If we see an input section and currently there is no group, start
// a new one. Skip any empty sections. We look at the data size
if (!this->input_sections().empty())
gold_error(_("Found non-EXIDX input sections in EXIDX output section"));
-
+
// Go through all the known input sections and record them.
typedef Unordered_set<Section_id, Section_id_hash> Section_id_set;
typedef Unordered_map<Section_id, const Output_section::Input_section*,
Task_lock_obj<Object> tl(task, exidx_relobj);
section_size_type exidx_size;
const unsigned char* exidx_contents =
- exidx_relobj->section_contents(exidx_shndx, &exidx_size, false);
+ exidx_relobj->section_contents(exidx_shndx, &exidx_size, false);
// Fix up coverage and append input section to output data list.
Arm_exidx_section_offset_map* section_offset_map = NULL;
uint32_t deleted_bytes =
- exidx_fixup.process_exidx_section<big_endian>(exidx_input_section,
+ exidx_fixup.process_exidx_section<big_endian>(exidx_input_section,
exidx_contents,
exidx_size,
§ion_offset_map);
this->add_script_input_section(*pis);
}
- processed_input_sections.insert(Section_id(exidx_relobj, exidx_shndx));
+ processed_input_sections.insert(Section_id(exidx_relobj, exidx_shndx));
}
// Insert an EXIDX_CANTUNWIND entry at the end of output if necessary.
arm_relobj->set_output_local_symbol_count_needs_update();
}
}
-
+
// Link exidx output section to the first seen output section and
// set correct entry size.
this->set_link_section(exidx_fixup.first_output_text_section());
// scan. There are two reasons. First, we should look at THUMB code and
// THUMB code only. Second, we only want to look at the 4K-page boundary
// to speed up the scanning.
-
+
while (p != this->mapping_symbols_info_.end()
&& p->first.first == shndx)
{
span_end = convert_to_section_size_type(next->first.second);
else
span_end = convert_to_section_size_type(shdr.get_sh_size());
-
+
if (((span_start + output_address) & ~0xfffUL)
!= ((span_end + output_address - 1) & ~0xfffUL))
{
}
}
- p = next;
+ p = next;
}
}
// do_count_local_symbol in parent and scan local symbols to mark
// THUMB functions. This is not the most efficient way but I do not want to
// slow down other ports by calling a per symbol target hook inside
-// Sized_relobj_file<size, big_endian>::do_count_local_symbols.
+// Sized_relobj_file<size, big_endian>::do_count_local_symbols.
template<bool big_endian>
void
{
// We need to fix-up the values of any local symbols whose type are
// STT_ARM_TFUNC.
-
+
// Ask parent to count the local symbols.
Sized_relobj_file<32, big_endian>::do_count_local_symbols(pool, dynpool);
const unsigned int loccount = this->local_symbol_count();
if (strtabshdr.get_sh_type() != elfcpp::SHT_STRTAB)
{
this->error(_("symbol table name section has wrong type: %u"),
- static_cast<unsigned int>(strtabshdr.get_sh_type()));
+ static_cast<unsigned int>(strtabshdr.get_sh_type()));
return;
}
const char* pnames =
{
// Call parent to relocate sections.
Sized_relobj_file<32, big_endian>::do_relocate_sections(symtab, layout,
- pshdrs, of, pviews);
+ pshdrs, of, pviews);
// We do not generate stubs if doing a relocatable link.
if (parameters->options().relocatable())
unsigned char* view = (*pviews)[i].view + offset;
Arm_address address = stub_table->address();
section_size_type view_size = stub_table->data_size();
-
+
stub_table->relocate_stubs(&relinfo, arm_target, os, view, address,
view_size);
}
unsigned int* pshndx)
{
elfcpp::Shdr<32, big_endian> shdr(pshdr);
-
+
// If there is no relocation, we cannot find the linked text section.
size_t reloc_size;
if (shdr.get_sh_type() == elfcpp::SHT_REL)
else
reloc_size = elfcpp::Elf_sizes<32>::rela_size;
size_t reloc_count = shdr.get_sh_size() / reloc_size;
-
+
// Get the relocations.
const unsigned char* prelocs =
- this->get_view(shdr.get_sh_offset(), shdr.get_sh_size(), true, false);
+ this->get_view(shdr.get_sh_offset(), shdr.get_sh_size(), true, false);
// Find the REL31 relocation for the first word of the first EXIDX entry.
for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size)
this->section_name(shndx).c_str(), shndx, text_shndx,
this->name().c_str());
exidx_input_section->set_has_errors();
- }
+ }
else if (this->exidx_section_map_[text_shndx] != NULL)
{
unsigned other_exidx_shndx =
if (shdr.get_sh_type() == elfcpp::SHT_ARM_ATTRIBUTES)
{
- gold_assert(this->attributes_section_data_ == NULL);
+ gold_assert(this->attributes_section_data_ == NULL);
section_offset_type section_offset = shdr.get_sh_offset();
section_size_type section_size =
convert_to_section_size_type(shdr.get_sh_size());
return;
}
- // Some tools are broken and they do not set the link of EXIDX sections.
+ // Some tools are broken and they do not set the link of EXIDX sections.
// We look at the first relocation to figure out the linked sections.
if (!deferred_exidx_sections.empty())
{
const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(),
locsize, true, true);
- // Process the deferred EXIDX sections.
+ // Process the deferred EXIDX sections.
for (unsigned int i = 0; i < deferred_exidx_sections.size(); ++i)
{
unsigned int shndx = deferred_exidx_sections[i];
}
// Process relocations for garbage collection. The ARM target uses .ARM.exidx
-// sections for unwinding. These sections are referenced implicitly by
+// sections for unwinding. These sections are referenced implicitly by
// text sections linked in the section headers. If we ignore these implicit
// references, the .ARM.exidx sections and any .ARM.extab sections they use
// will be garbage-collected incorrectly. Hence we override the same function
// This happens when --icf is used but --gc-sections is not.
if (!parameters->options().gc_sections())
return;
-
+
unsigned int shnum = this->shnum();
const unsigned int shdr_size = elfcpp::Elf_sizes<32>::shdr_size;
const unsigned char* pshdrs = this->get_view(this->elf_file()->shoff(),
// that is discarded due to entry merging.
lv.set_no_output_symtab_entry();
continue;
- }
+ }
}
}
const typename Reloc_types<elfcpp::SHT_REL, 32, big_endian>::Reloc&) const
{
typedef class Arm_relocate_functions<big_endian> RelocFuncs;
-
+
switch (r_type)
{
case elfcpp::R_ARM_CALL:
// We are doing a static link. Just mark it as belong to module 1,
// the executable.
unsigned int got_offset = this->add_constant(1);
- gsym->set_got_offset(got_type, got_offset);
+ gsym->set_got_offset(got_type, got_offset);
got_offset = this->add_constant(0);
this->static_relocs_.push_back(Static_reloc(got_offset,
elfcpp::R_ARM_TLS_DTPOFF32,
unsigned int got_offset = this->add_constant(1);
object->set_local_got_offset(index, got_type, got_offset);
got_offset = this->add_constant(0);
- this->static_relocs_.push_back(Static_reloc(got_offset,
- elfcpp::R_ARM_TLS_DTPOFF32,
+ this->static_relocs_.push_back(Static_reloc(got_offset,
+ elfcpp::R_ARM_TLS_DTPOFF32,
object, index));
}
Output_segment* tls_segment = this->layout_->tls_segment();
gold_assert(tls_segment != NULL);
-
+
// The thread pointer $tp points to the TCB, which is followed by the
// TLS. So we need to adjust $tp relative addressing by this amount.
Arm_address aligned_tcb_size =
for (size_t i = 0; i < this->static_relocs_.size(); ++i)
{
Static_reloc& reloc(this->static_relocs_[i]);
-
+
Arm_address value;
if (!reloc.symbol_is_global())
{
reloc.index(), reloc.relobj()->name().c_str());
continue;
}
-
+
value = psymval->value(object, 0);
}
else
}
// A class to handle the PLT data.
+// This is an abstract base class that handles most of the linker details
+// but does not know the actual contents of PLT entries. The derived
+// classes below fill in those details.
template<bool big_endian>
class Output_data_plt_arm : public Output_section_data
typedef Output_data_reloc<elfcpp::SHT_REL, true, 32, big_endian>
Reloc_section;
- Output_data_plt_arm(Layout*, Output_data_space*);
+ Output_data_plt_arm(Layout*, uint64_t addralign, Output_data_space*);
// Add an entry to the PLT.
void
{ return this->count_; }
// Return the offset of the first non-reserved PLT entry.
- static unsigned int
- first_plt_entry_offset()
- { return sizeof(first_plt_entry); }
+ unsigned int
+ first_plt_entry_offset() const
+ { return this->do_first_plt_entry_offset(); }
// Return the size of a PLT entry.
- static unsigned int
- get_plt_entry_size()
- { return sizeof(plt_entry); }
+ unsigned int
+ get_plt_entry_size() const
+ { return this->do_get_plt_entry_size(); }
protected:
+ // Fill in the first PLT entry.
+ void
+ fill_first_plt_entry(unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address)
+ { this->do_fill_first_plt_entry(pov, got_address, plt_address); }
+
+ void
+ fill_plt_entry(unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset)
+ { do_fill_plt_entry(pov, got_address, plt_address, got_offset, plt_offset); }
+
+ virtual unsigned int
+ do_first_plt_entry_offset() const = 0;
+
+ virtual unsigned int
+ do_get_plt_entry_size() const = 0;
+
+ virtual void
+ do_fill_first_plt_entry(unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address) = 0;
+
+ virtual void
+ do_fill_plt_entry(unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset) = 0;
+
void
do_adjust_output_section(Output_section* os);
{ mapfile->print_output_data(this, _("** PLT")); }
private:
- // Template for the first PLT entry.
- static const uint32_t first_plt_entry[5];
-
- // Template for subsequent PLT entries.
- static const uint32_t plt_entry[3];
-
// Set the final size.
void
set_final_data_size()
{
- this->set_data_size(sizeof(first_plt_entry)
- + this->count_ * sizeof(plt_entry));
+ this->set_data_size(this->first_plt_entry_offset()
+ + this->count_ * this->get_plt_entry_size());
}
// Write out the PLT data.
template<bool big_endian>
Output_data_plt_arm<big_endian>::Output_data_plt_arm(Layout* layout,
+ uint64_t addralign,
Output_data_space* got_plt)
- : Output_section_data(4), got_plt_(got_plt), count_(0)
+ : Output_section_data(addralign), got_plt_(got_plt), count_(0)
{
this->rel_ = new Reloc_section(false);
layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL,
// Note that when setting the PLT offset we skip the initial
// reserved PLT entry.
- gsym->set_plt_offset((this->count_) * sizeof(plt_entry)
- + sizeof(first_plt_entry));
+ gsym->set_plt_offset((this->count_) * this->get_plt_entry_size()
+ + this->first_plt_entry_offset());
++this->count_;
// appear in the relocations.
}
+template<bool big_endian>
+class Output_data_plt_arm_standard : public Output_data_plt_arm<big_endian>
+{
+ public:
+ Output_data_plt_arm_standard(Layout* layout, Output_data_space* got_plt)
+ : Output_data_plt_arm<big_endian>(layout, 4, got_plt)
+ { }
+
+ protected:
+ // Return the offset of the first non-reserved PLT entry.
+ virtual unsigned int
+ do_first_plt_entry_offset() const
+ { return sizeof(first_plt_entry); }
+
+ // Return the size of a PLT entry.
+ virtual unsigned int
+ do_get_plt_entry_size() const
+ { return sizeof(plt_entry); }
+
+ virtual void
+ do_fill_first_plt_entry(unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address);
+
+ virtual void
+ do_fill_plt_entry(unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset);
+
+ private:
+ // Template for the first PLT entry.
+ static const uint32_t first_plt_entry[5];
+
+ // Template for subsequent PLT entries.
+ static const uint32_t plt_entry[3];
+};
+
// ARM PLTs.
// FIXME: This is not very flexible. Right now this has only been tested
// on armv5te. If we are to support additional architecture features like
// The first entry in the PLT.
template<bool big_endian>
-const uint32_t Output_data_plt_arm<big_endian>::first_plt_entry[5] =
+const uint32_t Output_data_plt_arm_standard<big_endian>::first_plt_entry[5] =
{
0xe52de004, // str lr, [sp, #-4]!
0xe59fe004, // ldr lr, [pc, #4]
- 0xe08fe00e, // add lr, pc, lr
+ 0xe08fe00e, // add lr, pc, lr
0xe5bef008, // ldr pc, [lr, #8]!
0x00000000, // &GOT[0] - .
};
+template<bool big_endian>
+void
+Output_data_plt_arm_standard<big_endian>::do_fill_first_plt_entry(
+ unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address)
+{
+ // Write first PLT entry. All but the last word are constants.
+ const size_t num_first_plt_words = (sizeof(first_plt_entry)
+ / sizeof(plt_entry[0]));
+ for (size_t i = 0; i < num_first_plt_words - 1; i++)
+ elfcpp::Swap<32, big_endian>::writeval(pov + i * 4, first_plt_entry[i]);
+ // Last word in first PLT entry is &GOT[0] - .
+ elfcpp::Swap<32, big_endian>::writeval(pov + 16,
+ got_address - (plt_address + 16));
+}
+
// Subsequent entries in the PLT.
template<bool big_endian>
-const uint32_t Output_data_plt_arm<big_endian>::plt_entry[3] =
+const uint32_t Output_data_plt_arm_standard<big_endian>::plt_entry[3] =
{
0xe28fc600, // add ip, pc, #0xNN00000
0xe28cca00, // add ip, ip, #0xNN000
0xe5bcf000, // ldr pc, [ip, #0xNNN]!
};
+template<bool big_endian>
+void
+Output_data_plt_arm_standard<big_endian>::do_fill_plt_entry(
+ unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset)
+{
+ int32_t offset = ((got_address + got_offset)
+ - (plt_address + plt_offset + 8));
+
+ gold_assert(offset >= 0 && offset < 0x0fffffff);
+ uint32_t plt_insn0 = plt_entry[0] | ((offset >> 20) & 0xff);
+ elfcpp::Swap<32, big_endian>::writeval(pov, plt_insn0);
+ uint32_t plt_insn1 = plt_entry[1] | ((offset >> 12) & 0xff);
+ elfcpp::Swap<32, big_endian>::writeval(pov + 4, plt_insn1);
+ uint32_t plt_insn2 = plt_entry[2] | (offset & 0xfff);
+ elfcpp::Swap<32, big_endian>::writeval(pov + 8, plt_insn2);
+}
+
// Write out the PLT. This uses the hand-coded instructions above,
// and adjusts them as needed. This is all specified by the arm ELF
// Processor Supplement.
Arm_address plt_address = this->address();
Arm_address got_address = this->got_plt_->address();
- // Write first PLT entry. All but the last word are constants.
- const size_t num_first_plt_words = (sizeof(first_plt_entry)
- / sizeof(plt_entry[0]));
- for (size_t i = 0; i < num_first_plt_words - 1; i++)
- elfcpp::Swap<32, big_endian>::writeval(pov + i * 4, first_plt_entry[i]);
- // Last word in first PLT entry is &GOT[0] - .
- elfcpp::Swap<32, big_endian>::writeval(pov + 16,
- got_address - (plt_address + 16));
- pov += sizeof(first_plt_entry);
+ // Write first PLT entry.
+ this->fill_first_plt_entry(pov, got_address, plt_address);
+ pov += this->first_plt_entry_offset();
unsigned char* got_pov = got_view;
memset(got_pov, 0, 12);
got_pov += 12;
- const int rel_size = elfcpp::Elf_sizes<32>::rel_size;
- unsigned int plt_offset = sizeof(first_plt_entry);
- unsigned int plt_rel_offset = 0;
+ unsigned int plt_offset = this->first_plt_entry_offset();
unsigned int got_offset = 12;
const unsigned int count = this->count_;
for (unsigned int i = 0;
i < count;
++i,
- pov += sizeof(plt_entry),
+ pov += this->get_plt_entry_size(),
got_pov += 4,
- plt_offset += sizeof(plt_entry),
- plt_rel_offset += rel_size,
+ plt_offset += this->get_plt_entry_size(),
got_offset += 4)
{
// Set and adjust the PLT entry itself.
- int32_t offset = ((got_address + got_offset)
- - (plt_address + plt_offset + 8));
-
- gold_assert(offset >= 0 && offset < 0x0fffffff);
- uint32_t plt_insn0 = plt_entry[0] | ((offset >> 20) & 0xff);
- elfcpp::Swap<32, big_endian>::writeval(pov, plt_insn0);
- uint32_t plt_insn1 = plt_entry[1] | ((offset >> 12) & 0xff);
- elfcpp::Swap<32, big_endian>::writeval(pov + 4, plt_insn1);
- uint32_t plt_insn2 = plt_entry[2] | (offset & 0xfff);
- elfcpp::Swap<32, big_endian>::writeval(pov + 8, plt_insn2);
+ this->fill_plt_entry(pov, got_address, plt_address,
+ got_offset, plt_offset);
// Set the entry in the GOT.
elfcpp::Swap<32, big_endian>::writeval(got_pov, plt_address);
// Create the GOT sections first.
this->got_section(symtab, layout);
- this->plt_ = new Output_data_plt_arm<big_endian>(layout, this->got_plt_);
+ this->plt_ = this->make_data_plt(layout, this->got_plt_);
+
layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_EXECINSTR),
unsigned int
Target_arm<big_endian>::first_plt_entry_offset() const
{
- return Output_data_plt_arm<big_endian>::first_plt_entry_offset();
+ return this->plt_->first_plt_entry_offset();
}
// Return the size of each PLT entry.
unsigned int
Target_arm<big_endian>::plt_entry_size() const
{
- return Output_data_plt_arm<big_endian>::get_plt_entry_size();
+ return this->plt_->get_plt_entry_size();
}
// Get the section to use for TLS_DESC relocations.
{
Reloc_section* rel_dyn = target->rel_dyn_section(layout);
unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
- // If we are to add more other reloc types than R_ARM_ABS32,
- // we need to add check_non_pic(object, r_type) here.
+ // If we are to add more other reloc types than R_ARM_ABS32,
+ // we need to add check_non_pic(object, r_type) here.
rel_dyn->add_local_relative(object, r_sym, elfcpp::R_ARM_RELATIVE,
output_section, data_shndx,
reloc.get_r_offset());
// data section, we need to be careful not to apply this
// relocation statically.
if (parameters->options().output_is_position_independent())
- {
+ {
check_non_pic(object, r_type);
- Reloc_section* rel_dyn = target->rel_dyn_section(layout);
+ Reloc_section* rel_dyn = target->rel_dyn_section(layout);
unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
- if (lsym.get_st_type() != elfcpp::STT_SECTION)
+ if (lsym.get_st_type() != elfcpp::STT_SECTION)
rel_dyn->add_local(object, r_sym, r_type, output_section,
data_shndx, reloc.get_r_offset());
- else
- {
- gold_assert(lsym.get_st_value() == 0);
+ else
+ {
+ gold_assert(lsym.get_st_value() == 0);
unsigned int shndx = lsym.get_st_shndx();
bool is_ordinary;
shndx = object->adjust_sym_shndx(r_sym, shndx,
rel_dyn->add_local_section(object, shndx,
r_type, output_section,
data_shndx, reloc.get_r_offset());
- }
- }
+ }
+ }
break;
case elfcpp::R_ARM_REL32:
{
bool output_is_shared = parameters->options().shared();
const tls::Tls_optimization optimized_type
- = Target_arm<big_endian>::optimize_tls_reloc(!output_is_shared,
+ = Target_arm<big_endian>::optimize_tls_reloc(!output_is_shared,
r_type);
switch (r_type)
{
case elfcpp::R_ARM_TLS_GD32: // Global-dynamic
if (optimized_type == tls::TLSOPT_NONE)
{
- // Create a pair of GOT entries for the module index and
- // dtv-relative offset.
- Arm_output_data_got<big_endian>* got
- = target->got_section(symtab, layout);
- unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
+ // Create a pair of GOT entries for the module index and
+ // dtv-relative offset.
+ Arm_output_data_got<big_endian>* got
+ = target->got_section(symtab, layout);
+ unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
unsigned int shndx = lsym.get_st_shndx();
bool is_ordinary;
shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
case elfcpp::R_ARM_TLS_LDM32: // Local-dynamic
if (optimized_type == tls::TLSOPT_NONE)
{
- // Create a GOT entry for the module index.
- target->got_mod_index_entry(symtab, layout, object);
+ // Create a GOT entry for the module index.
+ target->got_mod_index_entry(symtab, layout, object);
}
else
// FIXME: TLS optimization not supported yet.
layout->set_has_static_tls();
if (output_is_shared)
{
- // We need to create a dynamic relocation.
- gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION);
- unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
+ // We need to create a dynamic relocation.
+ gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION);
+ unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
Reloc_section* rel_dyn = target->rel_dyn_section(layout);
rel_dyn->add_local(object, r_sym, elfcpp::R_ARM_TLS_TPOFF32,
output_section, data_shndx,
case elfcpp::R_ARM_ABS32_NOI:
// Absolute addressing relocations.
{
- // Make a PLT entry if necessary.
- if (this->symbol_needs_plt_entry(gsym))
- {
- target->make_plt_entry(symtab, layout, gsym);
- // Since this is not a PC-relative relocation, we may be
- // taking the address of a function. In that case we need to
- // set the entry in the dynamic symbol table to the address of
- // the PLT entry.
- if (gsym->is_from_dynobj() && !parameters->options().shared())
- gsym->set_needs_dynsym_value();
- }
- // Make a dynamic relocation if necessary.
- if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
- {
- if (gsym->may_need_copy_reloc())
- {
- target->copy_reloc(symtab, layout, object,
- data_shndx, output_section, gsym, reloc);
- }
- else if ((r_type == elfcpp::R_ARM_ABS32
+ // Make a PLT entry if necessary.
+ if (this->symbol_needs_plt_entry(gsym))
+ {
+ target->make_plt_entry(symtab, layout, gsym);
+ // Since this is not a PC-relative relocation, we may be
+ // taking the address of a function. In that case we need to
+ // set the entry in the dynamic symbol table to the address of
+ // the PLT entry.
+ if (gsym->is_from_dynobj() && !parameters->options().shared())
+ gsym->set_needs_dynsym_value();
+ }
+ // Make a dynamic relocation if necessary.
+ if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
+ {
+ if (gsym->may_need_copy_reloc())
+ {
+ target->copy_reloc(symtab, layout, object,
+ data_shndx, output_section, gsym, reloc);
+ }
+ else if ((r_type == elfcpp::R_ARM_ABS32
|| r_type == elfcpp::R_ARM_ABS32_NOI)
- && gsym->can_use_relative_reloc(false))
- {
- Reloc_section* rel_dyn = target->rel_dyn_section(layout);
- rel_dyn->add_global_relative(gsym, elfcpp::R_ARM_RELATIVE,
- output_section, object,
- data_shndx, reloc.get_r_offset());
- }
- else
- {
+ && gsym->can_use_relative_reloc(false))
+ {
+ Reloc_section* rel_dyn = target->rel_dyn_section(layout);
+ rel_dyn->add_global_relative(gsym, elfcpp::R_ARM_RELATIVE,
+ output_section, object,
+ data_shndx, reloc.get_r_offset());
+ }
+ else
+ {
check_non_pic(object, r_type);
- Reloc_section* rel_dyn = target->rel_dyn_section(layout);
- rel_dyn->add_global(gsym, r_type, output_section, object,
- data_shndx, reloc.get_r_offset());
- }
- }
+ Reloc_section* rel_dyn = target->rel_dyn_section(layout);
+ rel_dyn->add_global(gsym, r_type, output_section, object,
+ data_shndx, reloc.get_r_offset());
+ }
+ }
}
break;
// We need a GOT section.
target->got_section(symtab, layout);
break;
-
+
case elfcpp::R_ARM_REL32:
case elfcpp::R_ARM_LDR_PC_G0:
case elfcpp::R_ARM_SBREL32:
{
const bool is_final = gsym->final_value_is_known();
const tls::Tls_optimization optimized_type
- = Target_arm<big_endian>::optimize_tls_reloc(is_final, r_type);
+ = Target_arm<big_endian>::optimize_tls_reloc(is_final, r_type);
switch (r_type)
{
case elfcpp::R_ARM_TLS_GD32: // Global-dynamic
if (optimized_type == tls::TLSOPT_NONE)
{
- // Create a pair of GOT entries for the module index and
- // dtv-relative offset.
- Arm_output_data_got<big_endian>* got
- = target->got_section(symtab, layout);
+ // Create a pair of GOT entries for the module index and
+ // dtv-relative offset.
+ Arm_output_data_got<big_endian>* got
+ = target->got_section(symtab, layout);
if (!parameters->doing_static_link())
got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_PAIR,
target->rel_dyn_section(layout),
case elfcpp::R_ARM_TLS_LDM32: // Local-dynamic
if (optimized_type == tls::TLSOPT_NONE)
{
- // Create a GOT entry for the module index.
- target->got_mod_index_entry(symtab, layout, object);
+ // Create a GOT entry for the module index.
+ target->got_mod_index_entry(symtab, layout, object);
}
else
// FIXME: TLS optimization not supported yet.
layout->set_has_static_tls();
if (parameters->options().shared())
{
- // We need to create a dynamic relocation.
- Reloc_section* rel_dyn = target->rel_dyn_section(layout);
- rel_dyn->add_global(gsym, elfcpp::R_ARM_TLS_TPOFF32,
+ // We need to create a dynamic relocation.
+ Reloc_section* rel_dyn = target->rel_dyn_section(layout);
+ rel_dyn->add_global(gsym, elfcpp::R_ARM_TLS_TPOFF32,
output_section, object,
- data_shndx, reloc.get_r_offset());
+ data_shndx, reloc.get_r_offset());
}
break;
arm_relobj->attributes_section_data());
merged_any_attributes = true;
}
- }
+ }
for (Input_objects::Dynobj_iterator p = input_objects->dynobj_begin();
p != input_objects->dynobj_end();
{
// If neither --fix-cortex-a8 nor --no-fix-cortex-a8 is used, turn on
// Cortex-A8 erratum workaround for ARMv7-A or ARMv7 with unknown
- // profile.
+ // profile.
const Object_attribute* cpu_arch_profile_attr =
this->get_aeabi_object_attribute(elfcpp::Tag_CPU_arch_profile);
this->fix_cortex_a8_ =
(cpu_arch_attr->int_value() == elfcpp::TAG_CPU_ARCH_V7
- && (cpu_arch_profile_attr->int_value() == 'A'
- || cpu_arch_profile_attr->int_value() == 0));
+ && (cpu_arch_profile_attr->int_value() == 'A'
+ || cpu_arch_profile_attr->int_value() == 0));
}
-
+
// Check if we can use V4BX interworking.
// The V4BX interworking stub contains BX instruction,
// which is not specified for some profiles.
if (this->fix_v4bx() == General_options::FIX_V4BX_INTERWORKING
&& !this->may_use_v4t_interworking())
gold_error(_("unable to provide V4BX reloc interworking fix up; "
- "the target profile does not support BX instruction"));
+ "the target profile does not support BX instruction"));
// Fill in some more dynamic tags.
const Reloc_section* rel_plt = (this->plt_ == NULL
if (!parameters->options().relocatable())
{
if (exidx_section != NULL
- && exidx_section->type() == elfcpp::SHT_ARM_EXIDX)
- {
- // For the ARM target, we need to add a PT_ARM_EXIDX segment for
- // the .ARM.exidx section.
- if (!layout->script_options()->saw_phdrs_clause())
- {
- gold_assert(layout->find_output_segment(elfcpp::PT_ARM_EXIDX, 0,
- 0)
- == NULL);
- Output_segment* exidx_segment =
- layout->make_output_segment(elfcpp::PT_ARM_EXIDX, elfcpp::PF_R);
- exidx_segment->add_output_section_to_nonload(exidx_section,
- elfcpp::PF_R);
- }
- }
+ && exidx_section->type() == elfcpp::SHT_ARM_EXIDX)
+ {
+ // For the ARM target, we need to add a PT_ARM_EXIDX segment for
+ // the .ARM.exidx section.
+ if (!layout->script_options()->saw_phdrs_clause())
+ {
+ gold_assert(layout->find_output_segment(elfcpp::PT_ARM_EXIDX, 0,
+ 0)
+ == NULL);
+ Output_segment* exidx_segment =
+ layout->make_output_segment(elfcpp::PT_ARM_EXIDX, elfcpp::PF_R);
+ exidx_segment->add_output_section_to_nonload(exidx_section,
+ elfcpp::PF_R);
+ }
+ }
}
// Create an .ARM.attributes section if we have merged any attributes
}
else
{
- // This is a local symbol. Determine if the final target is THUMB.
- // We saved this information when all the local symbols were read.
+ // This is a local symbol. Determine if the final target is THUMB.
+ // We saved this information when all the local symbols were read.
elfcpp::Elf_types<32>::Elf_WXword r_info = rel.get_r_info();
unsigned int r_sym = elfcpp::elf_r_sym<32>(r_info);
thumb_bit = object->local_symbol_is_thumb_function(r_sym) ? 1 : 0;
// Strip LSB if this points to a THUMB target.
if (thumb_bit != 0
- && reloc_property->uses_thumb_bit()
+ && reloc_property->uses_thumb_bit()
&& ((psymval->value(object, 0) & 1) != 0))
{
Arm_address stripped_value =
psymval->value(object, 0) & ~static_cast<Arm_address>(1);
symval.set_output_value(stripped_value);
psymval = &symval;
- }
+ }
// To look up relocation stubs, we need to pass the symbol table index of
// a local symbol.
relative_address_base = address & 0xfffffffcU;
break;
default:
- gold_unreachable();
+ gold_unreachable();
}
-
+
typename Arm_relocate_functions::Status reloc_status =
Arm_relocate_functions::STATUS_OKAY;
bool check_overflow = reloc_property->checks_overflow();
case elfcpp::R_ARM_THM_MOVW_ABS_NC:
if (should_apply_static_reloc(gsym, r_type, false, output_section))
reloc_status = Arm_relocate_functions::thm_movw(view, object, psymval,
- 0, thumb_bit, false);
+ 0, thumb_bit, false);
break;
case elfcpp::R_ARM_THM_MOVT_ABS:
Arm_relocate_functions::thm_movt(view, object, psymval,
relative_address_base);
break;
-
+
case elfcpp::R_ARM_REL32:
reloc_status = Arm_relocate_functions::rel32(view, object, psymval,
address, thumb_bit);
&& !gsym->is_from_dynobj()
&& !gsym->is_preemptible()));
reloc_status =
- Arm_relocate_functions::arm_branch_common(
+ Arm_relocate_functions::arm_branch_common(
r_type, relinfo, view, gsym, object, r_sym, psymval, address,
thumb_bit, is_weakly_undefined_without_plt);
break;
switch (r_type)
{
case elfcpp::R_ARM_TLS_GD32: // Global-dynamic
- {
- unsigned int got_type = GOT_TYPE_TLS_PAIR;
- unsigned int got_offset;
- if (gsym != NULL)
- {
- gold_assert(gsym->has_got_offset(got_type));
- got_offset = gsym->got_offset(got_type) - target->got_size();
- }
- else
- {
- unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
- gold_assert(object->local_has_got_offset(r_sym, got_type));
- got_offset = (object->local_got_offset(r_sym, got_type)
+ {
+ unsigned int got_type = GOT_TYPE_TLS_PAIR;
+ unsigned int got_offset;
+ if (gsym != NULL)
+ {
+ gold_assert(gsym->has_got_offset(got_type));
+ got_offset = gsym->got_offset(got_type) - target->got_size();
+ }
+ else
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
+ gold_assert(object->local_has_got_offset(r_sym, got_type));
+ got_offset = (object->local_got_offset(r_sym, got_type)
- target->got_size());
- }
- if (optimized_type == tls::TLSOPT_NONE)
- {
+ }
+ if (optimized_type == tls::TLSOPT_NONE)
+ {
Arm_address got_entry =
target->got_plt_section()->address() + got_offset;
-
- // Relocate the field with the PC relative offset of the pair of
- // GOT entries.
+
+ // Relocate the field with the PC relative offset of the pair of
+ // GOT entries.
RelocFuncs::pcrel32_unaligned(view, got_entry, address);
- return ArmRelocFuncs::STATUS_OKAY;
- }
- }
+ return ArmRelocFuncs::STATUS_OKAY;
+ }
+ }
break;
case elfcpp::R_ARM_TLS_LDM32: // Local-dynamic
if (optimized_type == tls::TLSOPT_NONE)
- {
- // Relocate the field with the offset of the GOT entry for
- // the module index.
- unsigned int got_offset;
- got_offset = (target->got_mod_index_entry(NULL, NULL, NULL)
+ {
+ // Relocate the field with the offset of the GOT entry for
+ // the module index.
+ unsigned int got_offset;
+ got_offset = (target->got_mod_index_entry(NULL, NULL, NULL)
- target->got_size());
Arm_address got_entry =
target->got_plt_section()->address() + got_offset;
- // Relocate the field with the PC relative offset of the pair of
- // GOT entries.
- RelocFuncs::pcrel32_unaligned(view, got_entry, address);
+ // Relocate the field with the PC relative offset of the pair of
+ // GOT entries.
+ RelocFuncs::pcrel32_unaligned(view, got_entry, address);
return ArmRelocFuncs::STATUS_OKAY;
- }
+ }
break;
case elfcpp::R_ARM_TLS_LDO32: // Alternate local-dynamic
case elfcpp::R_ARM_TLS_IE32: // Initial-exec
if (optimized_type == tls::TLSOPT_NONE)
- {
- // Relocate the field with the offset of the GOT entry for
- // the tp-relative offset of the symbol.
+ {
+ // Relocate the field with the offset of the GOT entry for
+ // the tp-relative offset of the symbol.
unsigned int got_type = GOT_TYPE_TLS_OFFSET;
- unsigned int got_offset;
- if (gsym != NULL)
- {
- gold_assert(gsym->has_got_offset(got_type));
- got_offset = gsym->got_offset(got_type);
- }
- else
- {
- unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
- gold_assert(object->local_has_got_offset(r_sym, got_type));
- got_offset = object->local_got_offset(r_sym, got_type);
- }
-
- // All GOT offsets are relative to the end of the GOT.
- got_offset -= target->got_size();
+ unsigned int got_offset;
+ if (gsym != NULL)
+ {
+ gold_assert(gsym->has_got_offset(got_type));
+ got_offset = gsym->got_offset(got_type);
+ }
+ else
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
+ gold_assert(object->local_has_got_offset(r_sym, got_type));
+ got_offset = object->local_got_offset(r_sym, got_type);
+ }
+
+ // All GOT offsets are relative to the end of the GOT.
+ got_offset -= target->got_size();
Arm_address got_entry =
target->got_plt_section()->address() + got_offset;
- // Relocate the field with the PC relative offset of the GOT entry.
+ // Relocate the field with the PC relative offset of the GOT entry.
RelocFuncs::pcrel32_unaligned(view, got_entry, address);
return ArmRelocFuncs::STATUS_OKAY;
- }
+ }
break;
case elfcpp::R_ARM_TLS_LE32: // Local-exec
// If we're creating a shared library, a dynamic relocation will
// have been created for this location, so do not apply it now.
if (!parameters->options().shared())
- {
- gold_assert(tls_segment != NULL);
+ {
+ gold_assert(tls_segment != NULL);
// $tp points to the TCB, which is followed by the TLS, so we
// need to add TCB size to the offset.
Arm_address aligned_tcb_size =
align_address(ARM_TCB_SIZE, tls_segment->maximum_alignment());
- RelocFuncs::rel32_unaligned(view, value + aligned_tcb_size);
+ RelocFuncs::rel32_unaligned(view, value + aligned_tcb_size);
- }
+ }
return ArmRelocFuncs::STATUS_OKAY;
-
+
default:
gold_unreachable();
}
else
{
section_offset_type sot_offset =
- convert_types<section_offset_type, Arm_address>(offset);
+ convert_types<section_offset_type, Arm_address>(offset);
section_offset_type new_sot_offset =
- output_section->output_offset(object, relinfo->data_shndx,
- sot_offset);
+ output_section->output_offset(object, relinfo->data_shndx,
+ sot_offset);
gold_assert(new_sot_offset != -1);
new_offset = new_sot_offset;
}
{
new_offset += view_address;
if (offset_in_output_section != invalid_address)
- new_offset -= offset_in_output_section;
+ new_offset -= offset_in_output_section;
}
reloc_write.put_r_offset(new_offset);
Arm_address thumb_bit =
object->local_symbol_is_thumb_function(r_sym) ? 1 : 0;
if (thumb_bit != 0
- && arp->uses_thumb_bit()
+ && arp->uses_thumb_bit()
&& ((psymval->value(object, 0) & 1) != 0))
{
Arm_address stripped_value =
psymval->value(object, 0) & ~static_cast<Arm_address>(1);
symval.set_output_value(stripped_value);
psymval = &symval;
- }
+ }
unsigned char* paddend = view + offset;
typename Arm_relocate_functions<big_endian>::Status reloc_status =
case elfcpp::R_ARM_JUMP24:
case elfcpp::R_ARM_XPC25:
reloc_status =
- Arm_relocate_functions<big_endian>::arm_branch_common(
+ Arm_relocate_functions<big_endian>::arm_branch_common(
r_type, relinfo, paddend, NULL, object, 0, psymval, 0, thumb_bit,
false);
break;
|| (et == elfcpp::ET_EXEC && input_file->just_symbols()))
{
Arm_relobj<big_endian>* obj =
- new Arm_relobj<big_endian>(name, input_file, offset, ehdr);
+ new Arm_relobj<big_endian>(name, input_file, offset, ehdr);
obj->setup();
return obj;
}
else if (et == elfcpp::ET_DYN)
{
Sized_dynobj<32, big_endian>* obj =
- new Arm_dynobj<big_endian>(name, input_file, offset, ehdr);
+ new Arm_dynobj<big_endian>(name, input_file, offset, ehdr);
obj->setup();
return obj;
}
else
{
gold_error(_("%s: unsupported ELF file type %d"),
- name.c_str(), et);
+ name.c_str(), et);
return NULL;
}
}
char buffer[100];
sprintf(buffer, "<unknown CPU value %u>", value);
return std::string(buffer);
- }
+ }
}
// Merge object attributes from input file called NAME with those of the
{
if (out_attr[elfcpp::Tag_MPextension_use].int_value() != 0
&& out_attr[elfcpp::Tag_MPextension_use_legacy].int_value()
- != out_attr[elfcpp::Tag_MPextension_use].int_value())
+ != out_attr[elfcpp::Tag_MPextension_use].int_value())
{
gold_error(_("%s has both the current and legacy "
"Tag_MPextension_use attributes"),
in_attr[elfcpp::Tag_ABI_VFP_args].int_value());
else if (in_attr[elfcpp::Tag_ABI_FP_number_model].int_value() != 0
&& parameters->options().warn_mismatch())
- gold_error(_("%s uses VFP register arguments, output does not"),
+ gold_error(_("%s uses VFP register arguments, output does not"),
name);
}
// the input attribute's value is zero or two then if the output
// attribute's value is one the output value is set to the input
// value, otherwise the output value must be the same as the
- // inputs. */
- if (in_attr[i].int_value() != 1 && out_attr[i].int_value() != 1)
- {
+ // inputs. */
+ if (in_attr[i].int_value() != 1 && out_attr[i].int_value() != 1)
+ {
if (in_attr[i].int_value() != out_attr[i].int_value())
{
gold_error(_("DIV usage mismatch between %s and output"),
name);
}
- }
+ }
if (in_attr[i].int_value() != 1)
- out_attr[i].set_int_value(in_attr[i].int_value());
-
+ out_attr[i].set_int_value(in_attr[i].int_value());
+
break;
case elfcpp::Tag_MPextension_use_legacy:
!= in_attr[i].int_value())
{
gold_error(_("%s has has both the current and legacy "
- "Tag_MPextension_use attributes"),
+ "Tag_MPextension_use attributes"),
name);
}
}
err_tag = out_iter->first;
int saved_tag = out_iter->first;
delete out_iter->second;
- out_other_attributes->erase(out_iter);
+ out_other_attributes->erase(out_iter);
out_iter = out_other_attributes->upper_bound(saved_tag);
}
else if (in_iter != in_other_attributes->end()
// for this input section already.
gold_assert(ins.second);
- return arm_input_section;
+ return arm_input_section;
}
// Find the Arm_input_section object corresponding to the SHNDX-th input
psymval->value(arm_relobj, 0) & ~static_cast<Arm_address>(1);
symval.set_output_value(stripped_value);
psymval = &symval;
- }
+ }
// Get the symbol value.
Symbol_value<32>::Value value = psymval->value(arm_relobj, 0);
if (stub_type != arm_stub_none)
{
// Try looking up an existing stub from a stub table.
- Stub_table<big_endian>* stub_table =
+ Stub_table<big_endian>* stub_table =
arm_relobj->stub_table(relinfo->data_shndx);
gold_assert(stub_table != NULL);
-
+
// Locate stub by destination.
Reloc_stub::Key stub_key(stub_type, gsym, arm_relobj, r_sym, addend);
// Only a few relocation types need stubs.
if ((r_type != elfcpp::R_ARM_CALL)
- && (r_type != elfcpp::R_ARM_JUMP24)
- && (r_type != elfcpp::R_ARM_PLT32)
- && (r_type != elfcpp::R_ARM_THM_CALL)
- && (r_type != elfcpp::R_ARM_THM_XPC22)
- && (r_type != elfcpp::R_ARM_THM_JUMP24)
- && (r_type != elfcpp::R_ARM_THM_JUMP19)
- && (r_type != elfcpp::R_ARM_V4BX))
+ && (r_type != elfcpp::R_ARM_JUMP24)
+ && (r_type != elfcpp::R_ARM_PLT32)
+ && (r_type != elfcpp::R_ARM_THM_CALL)
+ && (r_type != elfcpp::R_ARM_THM_XPC22)
+ && (r_type != elfcpp::R_ARM_THM_JUMP24)
+ && (r_type != elfcpp::R_ARM_THM_JUMP19)
+ && (r_type != elfcpp::R_ARM_V4BX))
continue;
section_offset_type offset =
{
// create a new stub and add it to stub table.
Arm_v4bx_stub* stub =
- this->stub_factory().make_arm_v4bx_stub(reg);
+ this->stub_factory().make_arm_v4bx_stub(reg);
gold_assert(stub != NULL);
stub_table->add_arm_v4bx_stub(stub);
}
sym = NULL;
psymval = arm_object->local_symbol(r_sym);
- // If the local symbol belongs to a section we are discarding,
- // and that section is a debug section, try to find the
- // corresponding kept section and map this symbol to its
- // counterpart in the kept section. The symbol must not
- // correspond to a section we are folding.
+ // If the local symbol belongs to a section we are discarding,
+ // and that section is a debug section, try to find the
+ // corresponding kept section and map this symbol to its
+ // counterpart in the kept section. The symbol must not
+ // correspond to a section we are folding.
bool is_ordinary;
shndx = psymval->input_shndx(&is_ordinary);
is_defined_in_discarded_section =
typedef Sized_relobj_file<32, big_endian> ObjType;
typename ObjType::Compute_final_local_value_status status =
arm_object->compute_final_local_value(r_sym, psymval, &symval,
- relinfo->symtab);
+ relinfo->symtab);
if (status == ObjType::CFLV_OK)
{
// Currently we cannot handle a branch to a target in
else
{
// We cannot determine the final value.
- continue;
+ continue;
}
}
}
}
group_sections(layout, stub_group_size, stubs_always_after_branch, task);
-
+
// Also fix .ARM.exidx section coverage.
Arm_output_section<big_endian>* exidx_output_section = NULL;
for (Layout::Section_list::const_iterator p =
++sp)
(*sp)->remove_all_cortex_a8_stubs();
}
-
+
// Scan relocs for relocation stubs
for (Input_objects::Relobj_iterator op = input_objects->relobj_begin();
op != input_objects->relobj_end();
// Encoding T4: B<c>.W.
is_b = (insn & 0xf800d000U) == 0xf0009000U;
// Encoding T1: BL<c>.W.
- is_bl = (insn & 0xf800d000U) == 0xf000d000U;
- // Encoding T2: BLX<c>.W.
- is_blx = (insn & 0xf800d000U) == 0xf000c000U;
+ is_bl = (insn & 0xf800d000U) == 0xf000d000U;
+ // Encoding T2: BLX<c>.W.
+ is_blx = (insn & 0xf800d000U) == 0xf000c000U;
// Encoding T3: B<c>.W (not permitted in IT block).
is_bcc = ((insn & 0xf800d000U) == 0xf0008000U
&& (insn & 0x07f00000U) != 0x03800000U);
}
bool is_32bit_branch = is_b || is_bl || is_blx || is_bcc;
-
+
// If this instruction is a 32-bit THUMB branch that crosses a 4K
// page boundary and it follows 32-bit non-branch instruction,
// we need to work around.
offset = RelocFuncs::thumb32_branch_offset(upper_insn,
lower_insn);
if (is_blx)
- offset &= ~3;
+ offset &= ~3;
stub_type = (is_blx
? arm_stub_a8_veneer_blx
if (is_blx)
pc_for_insn &= ~3;
- // If we found a relocation, use the proper destination,
+ // If we found a relocation, use the proper destination,
// not the offset in the (unrelocated) instruction.
// Note this is always done if we switched the stub type above.
- if (cortex_a8_reloc != NULL)
- offset = (off_t) (cortex_a8_reloc->destination() - pc_for_insn);
+ if (cortex_a8_reloc != NULL)
+ offset = (off_t) (cortex_a8_reloc->destination() - pc_for_insn);
- Arm_address target = (pc_for_insn + offset) | (is_blx ? 0 : 1);
+ Arm_address target = (pc_for_insn + offset) | (is_blx ? 0 : 1);
// Add a new stub if destination address in in the same page.
- if (((address + i) & ~0xfffU) == (target & ~0xfffU))
- {
+ if (((address + i) & ~0xfffU) == (target & ~0xfffU))
+ {
Cortex_a8_stub* stub =
this->stub_factory_.make_cortex_a8_stub(stub_type,
arm_relobj, shndx,
arm_relobj->stub_table(shndx);
gold_assert(stub_table != NULL);
stub_table->add_cortex_a8_stub(address + i, stub);
- }
- }
- }
+ }
+ }
+ }
i += insn_32bit ? 4 : 2;
last_was_32bit = insn_32bit;
elfcpp::Swap<16, big_endian>::writeval(wv + 1, lower_insn);
}
+// Target selector for ARM. Note this is never instantiated directly.
+// It's only used in Target_selector_arm_nacl, below.
+
template<bool big_endian>
class Target_selector_arm : public Target_selector
{
Arm_output_section<big_endian>* arm_output_section =
Arm_output_section<big_endian>::as_arm_output_section(*p);
arm_output_section->append_text_sections_to_list(&sorted_text_sections);
- }
+ }
exidx_section->fix_exidx_coverage(layout, sorted_text_sections, symtab,
merge_exidx_entries(), task);
NULL, // version
Symbol_table::PREDEFINED,
exidx_section,
- 0, // value
+ 0, // value
0, // symsize
elfcpp::STT_NOTYPE,
elfcpp::STB_GLOBAL,
// Define __exidx_start and __exidx_end even when .ARM.exidx
// section is missing to match ld's behaviour.
symtab->define_as_constant("__exidx_start", NULL,
- Symbol_table::PREDEFINED,
- 0, 0, elfcpp::STT_OBJECT,
- elfcpp::STB_GLOBAL, elfcpp::STV_HIDDEN, 0,
- true, false);
+ Symbol_table::PREDEFINED,
+ 0, 0, elfcpp::STT_OBJECT,
+ elfcpp::STB_GLOBAL, elfcpp::STV_HIDDEN, 0,
+ true, false);
symtab->define_as_constant("__exidx_end", NULL,
- Symbol_table::PREDEFINED,
- 0, 0, elfcpp::STT_OBJECT,
- elfcpp::STB_GLOBAL, elfcpp::STV_HIDDEN, 0,
- true, false);
+ Symbol_table::PREDEFINED,
+ 0, 0, elfcpp::STT_OBJECT,
+ elfcpp::STB_GLOBAL, elfcpp::STV_HIDDEN, 0,
+ true, false);
}
}
-Target_selector_arm<false> target_selector_arm;
-Target_selector_arm<true> target_selector_armbe;
+// NaCl variant. It uses different PLT contents.
+
+template<bool big_endian>
+class Output_data_plt_arm_nacl;
+
+template<bool big_endian>
+class Target_arm_nacl : public Target_arm<big_endian>
+{
+ public:
+ Target_arm_nacl()
+ : Target_arm<big_endian>(&arm_nacl_info)
+ { }
+
+ protected:
+ virtual Output_data_plt_arm<big_endian>*
+ do_make_data_plt(Layout* layout, Output_data_space* got_plt)
+ { return new Output_data_plt_arm_nacl<big_endian>(layout, got_plt); }
+
+ private:
+ static const Target::Target_info arm_nacl_info;
+};
+
+template<bool big_endian>
+const Target::Target_info Target_arm_nacl<big_endian>::arm_nacl_info =
+{
+ 32, // size
+ big_endian, // is_big_endian
+ elfcpp::EM_ARM, // machine_code
+ false, // has_make_symbol
+ false, // has_resolve
+ false, // has_code_fill
+ true, // is_default_stack_executable
+ false, // can_icf_inline_merge_sections
+ '\0', // wrap_char
+ "/lib/ld-nacl-arm.so.1", // dynamic_linker
+ 0x20000, // default_text_segment_address
+ 0x10000, // abi_pagesize (overridable by -z max-page-size)
+ 0x10000, // common_pagesize (overridable by -z common-page-size)
+ true, // isolate_execinstr
+ 0x10000000, // rosegment_gap
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_UNDEF, // large_common_shndx
+ 0, // small_common_section_flags
+ 0, // large_common_section_flags
+ ".ARM.attributes", // attributes_section
+ "aeabi" // attributes_vendor
+};
+
+template<bool big_endian>
+class Output_data_plt_arm_nacl : public Output_data_plt_arm<big_endian>
+{
+ public:
+ Output_data_plt_arm_nacl(Layout* layout, Output_data_space* got_plt)
+ : Output_data_plt_arm<big_endian>(layout, 16, got_plt)
+ { }
+
+ protected:
+ // Return the offset of the first non-reserved PLT entry.
+ virtual unsigned int
+ do_first_plt_entry_offset() const
+ { return sizeof(first_plt_entry); }
+
+ // Return the size of a PLT entry.
+ virtual unsigned int
+ do_get_plt_entry_size() const
+ { return sizeof(plt_entry); }
+
+ virtual void
+ do_fill_first_plt_entry(unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address);
+
+ virtual void
+ do_fill_plt_entry(unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset);
+
+ private:
+ inline uint32_t arm_movw_immediate(uint32_t value)
+ {
+ return (value & 0x00000fff) | ((value & 0x0000f000) << 4);
+ }
+
+ inline uint32_t arm_movt_immediate(uint32_t value)
+ {
+ return ((value & 0x0fff0000) >> 16) | ((value & 0xf0000000) >> 12);
+ }
+
+ // Template for the first PLT entry.
+ static const uint32_t first_plt_entry[16];
+
+ // Template for subsequent PLT entries.
+ static const uint32_t plt_entry[4];
+};
+
+// The first entry in the PLT.
+template<bool big_endian>
+const uint32_t Output_data_plt_arm_nacl<big_endian>::first_plt_entry[16] =
+{
+ // First bundle:
+ 0xe300c000, // movw ip, #:lower16:&GOT[2]-.+8
+ 0xe340c000, // movt ip, #:upper16:&GOT[2]-.+8
+ 0xe08cc00f, // add ip, ip, pc
+ 0xe52dc008, // str ip, [sp, #-8]!
+ // Second bundle:
+ 0xe7dfcf1f, // bfc ip, #30, #2
+ 0xe59cc000, // ldr ip, [ip]
+ 0xe3ccc13f, // bic ip, ip, #0xc000000f
+ 0xe12fff1c, // bx ip
+ // Third bundle:
+ 0xe320f000, // nop
+ 0xe320f000, // nop
+ 0xe320f000, // nop
+ // .Lplt_tail:
+ 0xe50dc004, // str ip, [sp, #-4]
+ // Fourth bundle:
+ 0xe7dfcf1f, // bfc ip, #30, #2
+ 0xe59cc000, // ldr ip, [ip]
+ 0xe3ccc13f, // bic ip, ip, #0xc000000f
+ 0xe12fff1c, // bx ip
+};
+
+template<bool big_endian>
+void
+Output_data_plt_arm_nacl<big_endian>::do_fill_first_plt_entry(
+ unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address)
+{
+ // Write first PLT entry. All but first two words are constants.
+ const size_t num_first_plt_words = (sizeof(first_plt_entry)
+ / sizeof(first_plt_entry[0]));
+
+ int32_t got_displacement = got_address + 8 - (plt_address + 16);
+
+ elfcpp::Swap<32, big_endian>::writeval
+ (pov + 0, first_plt_entry[0] | arm_movw_immediate (got_displacement));
+ elfcpp::Swap<32, big_endian>::writeval
+ (pov + 4, first_plt_entry[1] | arm_movt_immediate (got_displacement));
+
+ for (size_t i = 2; i < num_first_plt_words; ++i)
+ elfcpp::Swap<32, big_endian>::writeval(pov + i * 4, first_plt_entry[i]);
+}
+
+// Subsequent entries in the PLT.
+
+template<bool big_endian>
+const uint32_t Output_data_plt_arm_nacl<big_endian>::plt_entry[4] =
+{
+ 0xe300c000, // movw ip, #:lower16:&GOT[n]-.+8
+ 0xe340c000, // movt ip, #:upper16:&GOT[n]-.+8
+ 0xe08cc00f, // add ip, ip, pc
+ 0xea000000, // b .Lplt_tail
+};
+
+template<bool big_endian>
+void
+Output_data_plt_arm_nacl<big_endian>::do_fill_plt_entry(
+ unsigned char* pov,
+ Arm_address got_address,
+ Arm_address plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset)
+{
+ // Calculate the displacement between the PLT slot and the
+ // common tail that's part of the special initial PLT slot.
+ int32_t tail_displacement = (plt_address + (11 * sizeof(uint32_t))
+ - (plt_address + plt_offset
+ + sizeof(plt_entry) + sizeof(uint32_t)));
+ gold_assert((tail_displacement & 3) == 0);
+ tail_displacement >>= 2;
+
+ gold_assert ((tail_displacement & 0xff000000) == 0
+ || (-tail_displacement & 0xff000000) == 0);
+
+ // Calculate the displacement between the PLT slot and the entry
+ // in the GOT. The offset accounts for the value produced by
+ // adding to pc in the penultimate instruction of the PLT stub.
+ const int32_t got_displacement = (got_address + got_offset
+ - (plt_address + sizeof(plt_entry)));
+
+ elfcpp::Swap<32, big_endian>::writeval
+ (pov + 0, plt_entry[0] | arm_movw_immediate (got_displacement));
+ elfcpp::Swap<32, big_endian>::writeval
+ (pov + 4, plt_entry[1] | arm_movt_immediate (got_displacement));
+ elfcpp::Swap<32, big_endian>::writeval
+ (pov + 8, plt_entry[2]);
+ elfcpp::Swap<32, big_endian>::writeval
+ (pov + 12, plt_entry[3] | (tail_displacement & 0x00ffffff));
+}
+
+// Target selectors.
+
+template<bool big_endian>
+class Target_selector_arm_nacl
+ : public Target_selector_nacl<Target_selector_arm<big_endian>,
+ Target_arm_nacl<big_endian> >
+{
+ public:
+ Target_selector_arm_nacl()
+ : Target_selector_nacl<Target_selector_arm<big_endian>,
+ Target_arm_nacl<big_endian> >(
+ "arm",
+ big_endian ? "elf32-bigarm-nacl" : "elf32-littlearm-nacl",
+ big_endian ? "armelfb_nacl" : "armelf_nacl")
+ { }
+};
+
+Target_selector_arm_nacl<false> target_selector_arm;
+Target_selector_arm_nacl<true> target_selector_armbe;
} // End anonymous namespace.
// freebsd.h -- FreeBSD support for gold -*- C++ -*-
-// Copyright 2009, 2011 Free Software Foundation, Inc.
+// Copyright 2009, 2011, 2012 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
// If we see a FreeBSD input file, mark the output file as using
// FreeBSD.
virtual Target*
- do_recognize(int, int osabi, int)
+ do_recognize(Input_file*, off_t, int, int osabi, int)
{
Target* ret = this->instantiate_target();
if (osabi == elfcpp::ELFOSABI_FREEBSD)
ret->set_osabi(static_cast<elfcpp::ELFOSABI>(osabi));
return ret;
}
-
+
// Recognize two names.
virtual Target*
do_recognize_by_bfd_name(const char* name)
// gold.cc -- main linker functions
-// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012
+// Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
// This class arranges the tasks to process the relocs for garbage collection.
-class Gc_runner : public Task_function_runner
+class Gc_runner : public Task_function_runner
{
public:
Gc_runner(const General_options& options,
void
Gc_runner::run(Workqueue* workqueue, const Task* task)
{
- queue_middle_gc_tasks(this->options_, task, this->input_objects_,
- this->symtab_, this->layout_, workqueue,
- this->mapfile_);
+ queue_middle_gc_tasks(this->options_, task, this->input_objects_,
+ this->symtab_, this->layout_, workqueue,
+ this->mapfile_);
}
// Queue up the initial set of tasks for this link job.
{
workqueue->queue(new Task_function(new Gc_runner(options,
input_objects,
- symtab,
- layout,
- mapfile),
- this_blocker,
- "Task_function Gc_runner"));
+ symtab,
+ layout,
+ mapfile),
+ this_blocker,
+ "Task_function Gc_runner"));
}
else
{
workqueue->queue(new Task_function(new Middle_runner(options,
- input_objects,
- symtab,
- layout,
- mapfile),
- this_blocker,
- "Task_function Middle_runner"));
+ input_objects,
+ symtab,
+ layout,
+ mapfile),
+ this_blocker,
+ "Task_function Middle_runner"));
}
}
}
workqueue->queue(new Task_function(new Middle_runner(options,
- input_objects,
- symtab,
- layout,
- mapfile),
- this_blocker,
- "Task_function Middle_runner"));
+ input_objects,
+ symtab,
+ layout,
+ mapfile),
+ this_blocker,
+ "Task_function Middle_runner"));
}
// Queue up the middle set of tasks. These are the tasks which run
symtab->add_undefined_symbols_from_command_line(layout);
// If garbage collection was chosen, relocs have been read and processed
- // at this point by pre_middle_tasks. Layout can then be done for all
+ // at this point by pre_middle_tasks. Layout can then be done for all
// objects.
if (parameters->options().gc_sections())
{
// Find the start symbol if any.
Symbol* start_sym = symtab->lookup(parameters->entry());
if (start_sym != NULL)
- {
- bool is_ordinary;
- unsigned int shndx = start_sym->shndx(&is_ordinary);
- if (is_ordinary)
- {
- symtab->gc()->worklist().push(
- Section_id(start_sym->object(), shndx));
- }
- }
+ {
+ bool is_ordinary;
+ unsigned int shndx = start_sym->shndx(&is_ordinary);
+ if (is_ordinary)
+ {
+ symtab->gc()->worklist().push(
+ Section_id(start_sym->object(), shndx));
+ }
+ }
// Symbols named with -u should not be considered garbage.
symtab->gc_mark_undef_symbols(layout);
gold_assert(symtab->gc() != NULL);
symtab->gc()->do_transitive_closure();
}
- // If identical code folding (--icf) is chosen it makes sense to do it
- // only after garbage collection (--gc-sections) as we do not want to
+ // If identical code folding (--icf) is chosen it makes sense to do it
+ // only after garbage collection (--gc-sections) as we do not want to
// be folding sections that will be garbage.
if (parameters->options().icf_enabled())
{
symtab->icf()->find_identical_sections(input_objects, symtab);
}
- // Call Object::layout for the second time to determine the
- // output_sections for all referenced input sections. When
- // --gc-sections or --icf is turned on, Object::layout is
- // called twice. It is called the first time when the
+ // Call Object::layout for the second time to determine the
+ // output_sections for all referenced input sections. When
+ // --gc-sections or --icf is turned on, Object::layout is
+ // called twice. It is called the first time when the
// symbols are added.
if (parameters->options().gc_sections()
|| parameters->options().icf_enabled())
{
for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
- p != input_objects->relobj_end();
- ++p)
- {
- Task_lock_obj<Object> tlo(task, *p);
- (*p)->layout(symtab, layout, NULL);
- }
+ p != input_objects->relobj_end();
+ ++p)
+ {
+ Task_lock_obj<Object> tlo(task, *p);
+ (*p)->layout(symtab, layout, NULL);
+ }
}
/* If plugins have specified a section order, re-arrange input sections
{
for (Layout::Section_list::const_iterator p
= layout->section_list().begin();
- p != layout->section_list().end();
- ++p)
- (*p)->update_section_layout(layout->get_section_order_map());
+ p != layout->section_list().end();
+ ++p)
+ (*p)->update_section_layout(layout->get_section_order_map());
}
// Layout deferred objects due to plugins.
Plugin_manager* plugins = parameters->options().plugins();
gold_assert(plugins != NULL);
plugins->layout_deferred_objects();
- }
+ }
if (parameters->options().gc_sections()
|| parameters->options().icf_enabled())
{
for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
- p != input_objects->relobj_end();
- ++p)
- {
- // Update the value of output_section stored in rd.
- Read_relocs_data* rd = (*p)->get_relocs_data();
- for (Read_relocs_data::Relocs_list::iterator q = rd->relocs.begin();
- q != rd->relocs.end();
- ++q)
- {
- q->output_section = (*p)->output_section(q->data_shndx);
- q->needs_special_offset_handling =
- (*p)->is_output_section_offset_invalid(q->data_shndx);
- }
- }
+ p != input_objects->relobj_end();
+ ++p)
+ {
+ // Update the value of output_section stored in rd.
+ Read_relocs_data* rd = (*p)->get_relocs_data();
+ for (Read_relocs_data::Relocs_list::iterator q = rd->relocs.begin();
+ q != rd->relocs.end();
+ ++q)
+ {
+ q->output_section = (*p)->output_section(q->data_shndx);
+ q->needs_special_offset_handling =
+ (*p)->is_output_section_offset_invalid(q->data_shndx);
+ }
+ }
}
// We have to support the case of not seeing any input objects, and
// Define symbols from any linker scripts.
layout->define_script_symbols(symtab);
- // Attach sections to segments.
- layout->attach_sections_to_segments();
-
// TODO(csilvers): figure out a more principled way to get the target
Target* target = const_cast<Target*>(¶meters->target());
+
+ // Attach sections to segments.
+ layout->attach_sections_to_segments(target);
+
if (!parameters->options().relocatable())
{
// Predefine standard symbols.
|| parameters->options().icf_enabled())
{
for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
- p != input_objects->relobj_end();
- ++p)
+ p != input_objects->relobj_end();
+ ++p)
{
Task_token* next_blocker = new Task_token(true);
next_blocker->add_blocker();
- workqueue->queue(new Scan_relocs(symtab, layout, *p,
+ workqueue->queue(new Scan_relocs(symtab, layout, *p,
(*p)->get_relocs_data(),
this_blocker, next_blocker));
this_blocker = next_blocker;
// some of the sections, and thus change our minds about the types
// of references made to the symbols.
for (Input_objects::Relobj_iterator p = input_objects->relobj_begin();
- p != input_objects->relobj_end();
- ++p)
- {
+ p != input_objects->relobj_end();
+ ++p)
+ {
Task_token* next_blocker = new Task_token(true);
next_blocker->add_blocker();
- workqueue->queue(new Read_relocs(symtab, layout, *p, this_blocker,
+ workqueue->queue(new Read_relocs(symtab, layout, *p, this_blocker,
next_blocker));
this_blocker = next_blocker;
- }
+ }
}
if (this_blocker == NULL)
// blocker here so that we can run the layout task immediately.
this_blocker = new Task_token(true);
}
- else
+ else
{
// If we failed to open any input files, it's possible for
// THIS_BLOCKER to be NULL here. There's no real point in
workqueue->queue(new Task_function(new Layout_task_runner(options,
input_objects,
symtab,
- target,
+ target,
layout,
mapfile),
this_blocker,
#include "target-select.h"
#include "tls.h"
#include "freebsd.h"
+#include "nacl.h"
#include "gc.h"
namespace
using namespace gold;
// A class to handle the PLT data.
+// This is an abstract base class that handles most of the linker details
+// but does not know the actual contents of PLT entries. The derived
+// classes below fill in those details.
class Output_data_plt_i386 : public Output_section_data
{
public:
typedef Output_data_reloc<elfcpp::SHT_REL, true, 32, false> Reloc_section;
- Output_data_plt_i386(Layout*, Output_data_space*, Output_data_space*);
+ Output_data_plt_i386(Layout*, uint64_t addralign,
+ Output_data_space*, Output_data_space*);
// Add an entry to the PLT.
void
{ return this->count_ + this->irelative_count_; }
// Return the offset of the first non-reserved PLT entry.
- static unsigned int
+ unsigned int
first_plt_entry_offset()
- { return plt_entry_size; }
+ { return this->get_plt_entry_size(); }
// Return the size of a PLT entry.
- static unsigned int
- get_plt_entry_size()
- { return plt_entry_size; }
+ unsigned int
+ get_plt_entry_size() const
+ { return this->do_get_plt_entry_size(); }
// Return the PLT address to use for a global symbol.
uint64_t
uint64_t
address_for_local(const Relobj*, unsigned int symndx);
- protected:
+ // Add .eh_frame information for the PLT.
void
- do_adjust_output_section(Output_section* os);
+ add_eh_frame(Layout* layout)
+ { this->do_add_eh_frame(layout); }
- // Write to a map file.
+ protected:
+ // Fill the first PLT entry, given the pointer to the PLT section data
+ // and the runtime address of the GOT.
void
- do_print_to_mapfile(Mapfile* mapfile) const
- { mapfile->print_output_data(this, _("** PLT")); }
+ fill_first_plt_entry(unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr got_address)
+ { this->do_fill_first_plt_entry(pov, got_address); }
+
+ // Fill a normal PLT entry, given the pointer to the entry's data in the
+ // section, the runtime address of the GOT, the offset into the GOT of
+ // the corresponding slot, the offset into the relocation section of the
+ // corresponding reloc, and the offset of this entry within the whole
+ // PLT. Return the offset from this PLT entry's runtime address that
+ // should be used to compute the initial value of the GOT slot.
+ unsigned int
+ fill_plt_entry(unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr got_address,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_rel_offset)
+ {
+ return this->do_fill_plt_entry(pov, got_address, got_offset,
+ plt_offset, plt_rel_offset);
+ }
- private:
- // The size of an entry in the PLT.
- static const int plt_entry_size = 16;
+ virtual unsigned int
+ do_get_plt_entry_size() const = 0;
- // The first entry in the PLT for an executable.
- static const unsigned char exec_first_plt_entry[plt_entry_size];
+ virtual void
+ do_fill_first_plt_entry(unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr got_address) = 0;
- // The first entry in the PLT for a shared object.
- static const unsigned char dyn_first_plt_entry[plt_entry_size];
+ virtual unsigned int
+ do_fill_plt_entry(unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr got_address,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_rel_offset) = 0;
- // Other entries in the PLT for an executable.
- static const unsigned char exec_plt_entry[plt_entry_size];
+ virtual void
+ do_add_eh_frame(Layout*) = 0;
- // Other entries in the PLT for a shared object.
- static const unsigned char dyn_plt_entry[plt_entry_size];
+ void
+ do_adjust_output_section(Output_section* os);
+
+ // Write to a map file.
+ void
+ do_print_to_mapfile(Mapfile* mapfile) const
+ { mapfile->print_output_data(this, _("** PLT")); }
// The .eh_frame unwind information for the PLT.
+ // The CIE is common across variants of the PLT format.
static const int plt_eh_frame_cie_size = 16;
- static const int plt_eh_frame_fde_size = 32;
static const unsigned char plt_eh_frame_cie[plt_eh_frame_cie_size];
- static const unsigned char plt_eh_frame_fde[plt_eh_frame_fde_size];
+ private:
// Set the final size.
void
set_final_data_size()
{
this->set_data_size((this->count_ + this->irelative_count_ + 1)
- * plt_entry_size);
+ * this->get_plt_entry_size());
}
// Write out the PLT data.
std::vector<Local_ifunc> local_ifuncs_;
};
+// This is an abstract class for the standard PLT layout.
+// The derived classes below handle the actual PLT contents
+// for the executable (non-PIC) and shared-library (PIC) cases.
+// The unwind information is uniform across those two, so it's here.
+
+class Output_data_plt_i386_standard : public Output_data_plt_i386
+{
+ public:
+ Output_data_plt_i386_standard(Layout* layout,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ : Output_data_plt_i386(layout, plt_entry_size, got_plt, got_irelative)
+ { }
+
+ protected:
+ virtual unsigned int
+ do_get_plt_entry_size() const
+ { return plt_entry_size; }
+
+ virtual void
+ do_add_eh_frame(Layout* layout)
+ {
+ layout->add_eh_frame_for_plt(this, plt_eh_frame_cie, plt_eh_frame_cie_size,
+ plt_eh_frame_fde, plt_eh_frame_fde_size);
+ }
+
+ // The size of an entry in the PLT.
+ static const int plt_entry_size = 16;
+
+ // The .eh_frame unwind information for the PLT.
+ static const int plt_eh_frame_fde_size = 32;
+ static const unsigned char plt_eh_frame_fde[plt_eh_frame_fde_size];
+};
+
+// Actually fill the PLT contents for an executable (non-PIC).
+
+class Output_data_plt_i386_exec : public Output_data_plt_i386_standard
+{
+public:
+ Output_data_plt_i386_exec(Layout* layout,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ : Output_data_plt_i386_standard(layout, got_plt, got_irelative)
+ { }
+
+ protected:
+ virtual void
+ do_fill_first_plt_entry(unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr got_address);
+
+ virtual unsigned int
+ do_fill_plt_entry(unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr got_address,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_rel_offset);
+
+ private:
+ // The first entry in the PLT for an executable.
+ static const unsigned char first_plt_entry[plt_entry_size];
+
+ // Other entries in the PLT for an executable.
+ static const unsigned char plt_entry[plt_entry_size];
+};
+
+// Actually fill the PLT contents for a shared library (PIC).
+
+class Output_data_plt_i386_dyn : public Output_data_plt_i386_standard
+{
+ public:
+ Output_data_plt_i386_dyn(Layout* layout,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ : Output_data_plt_i386_standard(layout, got_plt, got_irelative)
+ { }
+
+ protected:
+ virtual void
+ do_fill_first_plt_entry(unsigned char* pov, elfcpp::Elf_types<32>::Elf_Addr);
+
+ virtual unsigned int
+ do_fill_plt_entry(unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_rel_offset);
+
+ private:
+ // The first entry in the PLT for a shared object.
+ static const unsigned char first_plt_entry[plt_entry_size];
+
+ // Other entries in the PLT for a shared object.
+ static const unsigned char plt_entry[plt_entry_size];
+};
+
// The i386 target class.
// TLS info comes from
// http://people.redhat.com/drepper/tls.pdf
public:
typedef Output_data_reloc<elfcpp::SHT_REL, true, 32, false> Reloc_section;
- Target_i386()
- : Sized_target<32, false>(&i386_info),
+ Target_i386(const Target::Target_info* info = &i386_info)
+ : Sized_target<32, false>(info),
got_(NULL), plt_(NULL), got_plt_(NULL), got_irelative_(NULL),
got_tlsdesc_(NULL), global_offset_table_(NULL), rel_dyn_(NULL),
rel_irelative_(NULL), copy_relocs_(elfcpp::R_386_COPY), dynbss_(NULL),
got_mod_index_offset_(-1U), tls_base_symbol_defined_(false)
{ }
- // Process the relocations to determine unreferenced sections for
+ // Process the relocations to determine unreferenced sections for
// garbage collection.
void
gc_process_relocs(Symbol_table* symtab,
- Layout* layout,
- Sized_relobj_file<32, false>* object,
- unsigned int data_shndx,
- unsigned int sh_type,
- const unsigned char* prelocs,
- size_t reloc_count,
- Output_section* output_section,
- bool needs_special_offset_handling,
- size_t local_symbol_count,
- const unsigned char* plocal_symbols);
+ Layout* layout,
+ Sized_relobj_file<32, false>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols);
// Scan the relocations to look for symbol adjustments.
void
unsigned int
plt_entry_size() const;
+ protected:
+ // Instantiate the plt_ member.
+ // This chooses the right PLT flavor for an executable or a shared object.
+ Output_data_plt_i386*
+ make_data_plt(Layout* layout,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative,
+ bool dyn)
+ { return this->do_make_data_plt(layout, got_plt, got_irelative, dyn); }
+
+ virtual Output_data_plt_i386*
+ do_make_data_plt(Layout* layout,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative,
+ bool dyn)
+ {
+ if (dyn)
+ return new Output_data_plt_i386_dyn(layout, got_plt, got_irelative);
+ else
+ return new Output_data_plt_i386_exec(layout, got_plt, got_irelative);
+ }
+
private:
// The class which scans relocations.
struct Scan
inline bool
local_reloc_may_be_function_pointer(Symbol_table* symtab, Layout* layout,
- Target_i386* target,
- Sized_relobj_file<32, false>* object,
- unsigned int data_shndx,
- Output_section* output_section,
- const elfcpp::Rel<32, false>& reloc,
+ Target_i386* target,
+ Sized_relobj_file<32, false>* object,
+ unsigned int data_shndx,
+ Output_section* output_section,
+ const elfcpp::Rel<32, false>& reloc,
unsigned int r_type,
- const elfcpp::Sym<32, false>& lsym);
+ const elfcpp::Sym<32, false>& lsym);
inline bool
global_reloc_may_be_function_pointer(Symbol_table* symtab, Layout* layout,
Target_i386* target,
- Sized_relobj_file<32, false>* object,
- unsigned int data_shndx,
- Output_section* output_section,
+ Sized_relobj_file<32, false>* object,
+ unsigned int data_shndx,
+ Output_section* output_section,
const elfcpp::Rel<32, false>& reloc,
unsigned int r_type,
- Symbol* gsym);
+ Symbol* gsym);
inline bool
possible_function_pointer_reloc(unsigned int r_type);
// Return whether the static relocation needs to be applied.
inline bool
should_apply_static_reloc(const Sized_symbol<32>* gsym,
- unsigned int r_type,
- bool is_32bit,
+ unsigned int r_type,
+ bool is_32bit,
Output_section* output_section);
// Do a relocation. Return false if the caller should not issue
// Do a TLS relocation.
inline void
relocate_tls(const Relocate_info<32, false>*, Target_i386* target,
- size_t relnum, const elfcpp::Rel<32, false>&,
+ size_t relnum, const elfcpp::Rel<32, false>&,
unsigned int r_type, const Sized_symbol<32>*,
const Symbol_value<32>*,
unsigned char*, elfcpp::Elf_types<32>::Elf_Addr,
// Add a potential copy relocation.
void
copy_reloc(Symbol_table* symtab, Layout* layout,
- Sized_relobj_file<32, false>* object,
+ Sized_relobj_file<32, false>* object,
unsigned int shndx, Output_section* output_section,
Symbol* sym, const elfcpp::Rel<32, false>& reloc)
{
0x08048000, // default_text_segment_address
0x1000, // abi_pagesize (overridable by -z max-page-size)
0x1000, // common_pagesize (overridable by -z common-page-size)
+ false, // isolate_execinstr
+ 0, // rosegment_gap
elfcpp::SHN_UNDEF, // small_common_shndx
elfcpp::SHN_UNDEF, // large_common_shndx
0, // small_common_section_flags
// section just for PLT entries.
Output_data_plt_i386::Output_data_plt_i386(Layout* layout,
+ uint64_t addralign,
Output_data_space* got_plt,
Output_data_space* got_irelative)
- : Output_section_data(16), layout_(layout), tls_desc_rel_(NULL),
+ : Output_section_data(addralign),
+ layout_(layout), tls_desc_rel_(NULL),
irelative_rel_(NULL), got_plt_(got_plt), got_irelative_(got_irelative),
count_(0), irelative_count_(0), global_ifuncs_(), local_ifuncs_()
{
layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL,
elfcpp::SHF_ALLOC, this->rel_,
ORDER_DYNAMIC_PLT_RELOCS, false);
-
- // Add unwind information if requested.
- if (parameters->options().ld_generated_unwind_info())
- layout->add_eh_frame_for_plt(this, plt_eh_frame_cie, plt_eh_frame_cie_size,
- plt_eh_frame_fde, plt_eh_frame_fde_size);
}
void
if (gsym->type() == elfcpp::STT_GNU_IFUNC
&& gsym->can_use_relative_reloc(false))
{
- gsym->set_plt_offset(this->irelative_count_ * plt_entry_size);
+ gsym->set_plt_offset(this->irelative_count_ * this->get_plt_entry_size());
++this->irelative_count_;
section_offset_type got_offset =
this->got_irelative_->current_data_size();
{
// When setting the PLT offset we skip the initial reserved PLT
// entry.
- gsym->set_plt_offset((this->count_ + 1) * plt_entry_size);
+ gsym->set_plt_offset((this->count_ + 1) * this->get_plt_entry_size());
++this->count_;
Sized_relobj_file<32, false>* relobj,
unsigned int local_sym_index)
{
- unsigned int plt_offset = this->irelative_count_ * plt_entry_size;
+ unsigned int plt_offset = this->irelative_count_ * this->get_plt_entry_size();
++this->irelative_count_;
section_offset_type got_offset = this->got_irelative_->current_data_size();
uint64_t offset = 0;
if (gsym->type() == elfcpp::STT_GNU_IFUNC
&& gsym->can_use_relative_reloc(false))
- offset = (this->count_ + 1) * plt_entry_size;
+ offset = (this->count_ + 1) * this->get_plt_entry_size();
return this->address() + offset;
}
uint64_t
Output_data_plt_i386::address_for_local(const Relobj*, unsigned int)
{
- return this->address() + (this->count_ + 1) * plt_entry_size;
+ return this->address() + (this->count_ + 1) * this->get_plt_entry_size();
}
// The first entry in the PLT for an executable.
-const unsigned char Output_data_plt_i386::exec_first_plt_entry[plt_entry_size] =
+const unsigned char Output_data_plt_i386_exec::first_plt_entry[plt_entry_size] =
{
0xff, 0x35, // pushl contents of memory address
0, 0, 0, 0, // replaced with address of .got + 4
0, 0, 0, 0 // unused
};
+void
+Output_data_plt_i386_exec::do_fill_first_plt_entry(
+ unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr got_address)
+{
+ memcpy(pov, first_plt_entry, plt_entry_size);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 2, got_address + 4);
+ elfcpp::Swap<32, false>::writeval(pov + 8, got_address + 8);
+}
+
// The first entry in the PLT for a shared object.
-const unsigned char Output_data_plt_i386::dyn_first_plt_entry[plt_entry_size] =
+const unsigned char Output_data_plt_i386_dyn::first_plt_entry[plt_entry_size] =
{
0xff, 0xb3, 4, 0, 0, 0, // pushl 4(%ebx)
0xff, 0xa3, 8, 0, 0, 0, // jmp *8(%ebx)
0, 0, 0, 0 // unused
};
+void
+Output_data_plt_i386_dyn::do_fill_first_plt_entry(
+ unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr)
+{
+ memcpy(pov, first_plt_entry, plt_entry_size);
+}
+
// Subsequent entries in the PLT for an executable.
-const unsigned char Output_data_plt_i386::exec_plt_entry[plt_entry_size] =
+const unsigned char Output_data_plt_i386_exec::plt_entry[plt_entry_size] =
{
0xff, 0x25, // jmp indirect
0, 0, 0, 0, // replaced with address of symbol in .got
0, 0, 0, 0 // replaced with offset to start of .plt
};
+unsigned int
+Output_data_plt_i386_exec::do_fill_plt_entry(
+ unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr got_address,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_rel_offset)
+{
+ memcpy(pov, plt_entry, plt_entry_size);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
+ got_address + got_offset);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 7, plt_rel_offset);
+ elfcpp::Swap<32, false>::writeval(pov + 12, - (plt_offset + 12 + 4));
+ return 6;
+}
+
// Subsequent entries in the PLT for a shared object.
-const unsigned char Output_data_plt_i386::dyn_plt_entry[plt_entry_size] =
+const unsigned char Output_data_plt_i386_dyn::plt_entry[plt_entry_size] =
{
0xff, 0xa3, // jmp *offset(%ebx)
0, 0, 0, 0, // replaced with offset of symbol in .got
0, 0, 0, 0 // replaced with offset to start of .plt
};
+unsigned int
+Output_data_plt_i386_dyn::do_fill_plt_entry(unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_rel_offset)
+{
+ memcpy(pov, plt_entry, plt_entry_size);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 2, got_offset);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 7, plt_rel_offset);
+ elfcpp::Swap<32, false>::writeval(pov + 12, - (plt_offset + 12 + 4));
+ return 6;
+}
+
// The .eh_frame unwind information for the PLT.
const unsigned char
};
const unsigned char
-Output_data_plt_i386::plt_eh_frame_fde[plt_eh_frame_fde_size] =
+Output_data_plt_i386_standard::plt_eh_frame_fde[plt_eh_frame_fde_size] =
{
0, 0, 0, 0, // Replaced with offset to .plt.
0, 0, 0, 0, // Replaced with size of .plt.
elfcpp::Elf_types<32>::Elf_Addr plt_address = this->address();
elfcpp::Elf_types<32>::Elf_Addr got_address = this->got_plt_->address();
- if (parameters->options().output_is_position_independent())
- memcpy(pov, dyn_first_plt_entry, plt_entry_size);
- else
- {
- memcpy(pov, exec_first_plt_entry, plt_entry_size);
- elfcpp::Swap_unaligned<32, false>::writeval(pov + 2, got_address + 4);
- elfcpp::Swap<32, false>::writeval(pov + 8, got_address + 8);
- }
- pov += plt_entry_size;
+ this->fill_first_plt_entry(pov, got_address);
+ pov += this->get_plt_entry_size();
unsigned char* got_pov = got_view;
const int rel_size = elfcpp::Elf_sizes<32>::rel_size;
- unsigned int plt_offset = plt_entry_size;
+ unsigned int plt_offset = this->get_plt_entry_size();
unsigned int plt_rel_offset = 0;
unsigned int got_offset = 12;
const unsigned int count = this->count_ + this->irelative_count_;
for (unsigned int i = 0;
i < count;
++i,
- pov += plt_entry_size,
+ pov += this->get_plt_entry_size(),
got_pov += 4,
- plt_offset += plt_entry_size,
+ plt_offset += this->get_plt_entry_size(),
plt_rel_offset += rel_size,
got_offset += 4)
{
// Set and adjust the PLT entry itself.
-
- if (parameters->options().output_is_position_independent())
- {
- memcpy(pov, dyn_plt_entry, plt_entry_size);
- elfcpp::Swap_unaligned<32, false>::writeval(pov + 2, got_offset);
- }
- else
- {
- memcpy(pov, exec_plt_entry, plt_entry_size);
- elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
- (got_address
- + got_offset));
- }
-
- elfcpp::Swap_unaligned<32, false>::writeval(pov + 7, plt_rel_offset);
- elfcpp::Swap<32, false>::writeval(pov + 12,
- - (plt_offset + plt_entry_size));
+ unsigned int lazy_offset = this->fill_plt_entry(pov,
+ got_address,
+ got_offset,
+ plt_offset,
+ plt_rel_offset);
// Set the entry in the GOT.
- elfcpp::Swap<32, false>::writeval(got_pov, plt_address + plt_offset + 6);
+ elfcpp::Swap<32, false>::writeval(got_pov,
+ plt_address + plt_offset + lazy_offset);
}
// If any STT_GNU_IFUNC symbols have PLT entries, we need to change
// Create the GOT sections first.
this->got_section(symtab, layout);
- this->plt_ = new Output_data_plt_i386(layout, this->got_plt_,
- this->got_irelative_);
+ const bool dyn = parameters->options().output_is_position_independent();
+ this->plt_ = this->make_data_plt(layout,
+ this->got_plt_,
+ this->got_irelative_,
+ dyn);
+
+ // Add unwind information if requested.
+ if (parameters->options().ld_generated_unwind_info())
+ this->plt_->add_eh_frame(layout);
+
layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_EXECINSTR),
unsigned int
Target_i386::first_plt_entry_offset() const
{
- return Output_data_plt_i386::first_plt_entry_offset();
+ return this->plt_->first_plt_entry_offset();
}
// Return the size of each PLT entry.
unsigned int
Target_i386::plt_entry_size() const
{
- return Output_data_plt_i386::get_plt_entry_size();
+ return this->plt_->get_plt_entry_size();
}
// Get the section to use for TLS_DESC relocations.
unsigned int
Target_i386::got_mod_index_entry(Symbol_table* symtab, Layout* layout,
- Sized_relobj_file<32, false>* object)
+ Sized_relobj_file<32, false>* object)
{
if (this->got_mod_index_offset_ == -1U)
{
Output_data_got<32, false>* got = this->got_section(symtab, layout);
unsigned int got_offset = got->add_constant(0);
rel_dyn->add_local(object, 0, elfcpp::R_386_TLS_DTPMOD32, got,
- got_offset);
+ got_offset);
got->add_constant(0);
this->got_mod_index_offset_ = got_offset;
}
int flags = Scan::get_reference_flags(r_type);
if (flags & Symbol::TLS_REF)
gold_error(_("%s: unsupported TLS reloc %u for IFUNC symbol"),
- object->name().c_str(), r_type);
+ object->name().c_str(), r_type);
return flags != 0;
}
inline void
Target_i386::Scan::local(Symbol_table* symtab,
- Layout* layout,
- Target_i386* target,
- Sized_relobj_file<32, false>* object,
- unsigned int data_shndx,
- Output_section* output_section,
- const elfcpp::Rel<32, false>& reloc,
- unsigned int r_type,
- const elfcpp::Sym<32, false>& lsym)
+ Layout* layout,
+ Target_i386* target,
+ Sized_relobj_file<32, false>* object,
+ unsigned int data_shndx,
+ Output_section* output_section,
+ const elfcpp::Rel<32, false>& reloc,
+ unsigned int r_type,
+ const elfcpp::Sym<32, false>& lsym)
{
// A local STT_GNU_IFUNC symbol may require a PLT entry.
if (lsym.get_st_type() == elfcpp::STT_GNU_IFUNC
// an R_386_RELATIVE relocation so the dynamic loader can
// relocate it easily.
if (parameters->options().output_is_position_independent())
- {
- Reloc_section* rel_dyn = target->rel_dyn_section(layout);
- unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
+ {
+ Reloc_section* rel_dyn = target->rel_dyn_section(layout);
+ unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
rel_dyn->add_local_relative(object, r_sym, elfcpp::R_386_RELATIVE,
output_section, data_shndx,
reloc.get_r_offset());
- }
+ }
break;
case elfcpp::R_386_16:
// data section, we need to be careful not to apply this
// relocation statically.
if (parameters->options().output_is_position_independent())
- {
- Reloc_section* rel_dyn = target->rel_dyn_section(layout);
+ {
+ Reloc_section* rel_dyn = target->rel_dyn_section(layout);
unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
- if (lsym.get_st_type() != elfcpp::STT_SECTION)
+ if (lsym.get_st_type() != elfcpp::STT_SECTION)
rel_dyn->add_local(object, r_sym, r_type, output_section,
data_shndx, reloc.get_r_offset());
- else
- {
- gold_assert(lsym.get_st_value() == 0);
+ else
+ {
+ gold_assert(lsym.get_st_value() == 0);
unsigned int shndx = lsym.get_st_shndx();
bool is_ordinary;
shndx = object->adjust_sym_shndx(r_sym, shndx,
rel_dyn->add_local_section(object, shndx,
r_type, output_section,
data_shndx, reloc.get_r_offset());
- }
- }
+ }
+ }
break;
case elfcpp::R_386_PC32:
case elfcpp::R_386_GOT32:
{
- // The symbol requires a GOT entry.
- Output_data_got<32, false>* got = target->got_section(symtab, layout);
- unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
+ // The symbol requires a GOT entry.
+ Output_data_got<32, false>* got = target->got_section(symtab, layout);
+ unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
// For a STT_GNU_IFUNC symbol we want the PLT offset. That
// lets function pointers compare correctly with shared
is_new = got->add_local_plt(object, r_sym, GOT_TYPE_STANDARD);
else
is_new = got->add_local(object, r_sym, GOT_TYPE_STANDARD);
- if (is_new)
- {
- // If we are generating a shared object, we need to add a
- // dynamic RELATIVE relocation for this symbol's GOT entry.
- if (parameters->options().output_is_position_independent())
- {
- Reloc_section* rel_dyn = target->rel_dyn_section(layout);
+ if (is_new)
+ {
+ // If we are generating a shared object, we need to add a
+ // dynamic RELATIVE relocation for this symbol's GOT entry.
+ if (parameters->options().output_is_position_independent())
+ {
+ Reloc_section* rel_dyn = target->rel_dyn_section(layout);
unsigned int got_offset =
object->local_got_offset(r_sym, GOT_TYPE_STANDARD);
rel_dyn->add_local_relative(object, r_sym,
elfcpp::R_386_RELATIVE,
got, got_offset);
- }
- }
+ }
+ }
}
break;
{
bool output_is_shared = parameters->options().shared();
const tls::Tls_optimization optimized_type
- = Target_i386::optimize_tls_reloc(!output_is_shared, r_type);
+ = Target_i386::optimize_tls_reloc(!output_is_shared, r_type);
switch (r_type)
{
case elfcpp::R_386_TLS_GD: // Global-dynamic
if (optimized_type == tls::TLSOPT_NONE)
{
- // Create a pair of GOT entries for the module index and
- // dtv-relative offset.
- Output_data_got<32, false>* got
- = target->got_section(symtab, layout);
- unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
+ // Create a pair of GOT entries for the module index and
+ // dtv-relative offset.
+ Output_data_got<32, false>* got
+ = target->got_section(symtab, layout);
+ unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
unsigned int shndx = lsym.get_st_shndx();
bool is_ordinary;
shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
if (!is_ordinary)
object->error(_("local symbol %u has bad shndx %u"),
r_sym, shndx);
- else
+ else
got->add_local_pair_with_rel(object, r_sym, shndx,
GOT_TYPE_TLS_PAIR,
target->rel_dyn_section(layout),
case elfcpp::R_386_TLS_GOTDESC: // Global-dynamic (from ~oliva)
target->define_tls_base_symbol(symtab, layout);
- if (optimized_type == tls::TLSOPT_NONE)
- {
- // Create a double GOT entry with an R_386_TLS_DESC
- // reloc. The R_386_TLS_DESC reloc is resolved
- // lazily, so the GOT entry needs to be in an area in
- // .got.plt, not .got. Call got_section to make sure
- // the section has been created.
+ if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Create a double GOT entry with an R_386_TLS_DESC
+ // reloc. The R_386_TLS_DESC reloc is resolved
+ // lazily, so the GOT entry needs to be in an area in
+ // .got.plt, not .got. Call got_section to make sure
+ // the section has been created.
target->got_section(symtab, layout);
- Output_data_got<32, false>* got = target->got_tlsdesc_section();
- unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
+ Output_data_got<32, false>* got = target->got_tlsdesc_section();
+ unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
if (!object->local_has_got_offset(r_sym, GOT_TYPE_TLS_DESC))
{
unsigned int got_offset = got->add_constant(0);
Reloc_section* rt = target->rel_tls_desc_section(layout);
rt->add_absolute(elfcpp::R_386_TLS_DESC, got, got_offset);
}
- }
- else if (optimized_type != tls::TLSOPT_TO_LE)
- unsupported_reloc_local(object, r_type);
+ }
+ else if (optimized_type != tls::TLSOPT_TO_LE)
+ unsupported_reloc_local(object, r_type);
break;
case elfcpp::R_386_TLS_DESC_CALL:
case elfcpp::R_386_TLS_LDM: // Local-dynamic
if (optimized_type == tls::TLSOPT_NONE)
{
- // Create a GOT entry for the module index.
- target->got_mod_index_entry(symtab, layout, object);
+ // Create a GOT entry for the module index.
+ target->got_mod_index_entry(symtab, layout, object);
}
else if (optimized_type != tls::TLSOPT_TO_LE)
unsupported_reloc_local(object, r_type);
layout->set_has_static_tls();
if (optimized_type == tls::TLSOPT_NONE)
{
- // For the R_386_TLS_IE relocation, we need to create a
- // dynamic relocation when building a shared library.
- if (r_type == elfcpp::R_386_TLS_IE
- && parameters->options().shared())
- {
- Reloc_section* rel_dyn = target->rel_dyn_section(layout);
- unsigned int r_sym
- = elfcpp::elf_r_sym<32>(reloc.get_r_info());
- rel_dyn->add_local_relative(object, r_sym,
- elfcpp::R_386_RELATIVE,
- output_section, data_shndx,
- reloc.get_r_offset());
- }
- // Create a GOT entry for the tp-relative offset.
- Output_data_got<32, false>* got
- = target->got_section(symtab, layout);
- unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
- unsigned int dyn_r_type = (r_type == elfcpp::R_386_TLS_IE_32
- ? elfcpp::R_386_TLS_TPOFF32
- : elfcpp::R_386_TLS_TPOFF);
- unsigned int got_type = (r_type == elfcpp::R_386_TLS_IE_32
- ? GOT_TYPE_TLS_OFFSET
- : GOT_TYPE_TLS_NOFFSET);
- got->add_local_with_rel(object, r_sym, got_type,
- target->rel_dyn_section(layout),
- dyn_r_type);
+ // For the R_386_TLS_IE relocation, we need to create a
+ // dynamic relocation when building a shared library.
+ if (r_type == elfcpp::R_386_TLS_IE
+ && parameters->options().shared())
+ {
+ Reloc_section* rel_dyn = target->rel_dyn_section(layout);
+ unsigned int r_sym
+ = elfcpp::elf_r_sym<32>(reloc.get_r_info());
+ rel_dyn->add_local_relative(object, r_sym,
+ elfcpp::R_386_RELATIVE,
+ output_section, data_shndx,
+ reloc.get_r_offset());
+ }
+ // Create a GOT entry for the tp-relative offset.
+ Output_data_got<32, false>* got
+ = target->got_section(symtab, layout);
+ unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
+ unsigned int dyn_r_type = (r_type == elfcpp::R_386_TLS_IE_32
+ ? elfcpp::R_386_TLS_TPOFF32
+ : elfcpp::R_386_TLS_TPOFF);
+ unsigned int got_type = (r_type == elfcpp::R_386_TLS_IE_32
+ ? GOT_TYPE_TLS_OFFSET
+ : GOT_TYPE_TLS_NOFFSET);
+ got->add_local_with_rel(object, r_sym, got_type,
+ target->rel_dyn_section(layout),
+ dyn_r_type);
}
else if (optimized_type != tls::TLSOPT_TO_LE)
unsupported_reloc_local(object, r_type);
layout->set_has_static_tls();
if (output_is_shared)
{
- // We need to create a dynamic relocation.
- gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION);
- unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
- unsigned int dyn_r_type = (r_type == elfcpp::R_386_TLS_LE_32
- ? elfcpp::R_386_TLS_TPOFF32
- : elfcpp::R_386_TLS_TPOFF);
- Reloc_section* rel_dyn = target->rel_dyn_section(layout);
- rel_dyn->add_local(object, r_sym, dyn_r_type, output_section,
- data_shndx, reloc.get_r_offset());
+ // We need to create a dynamic relocation.
+ gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION);
+ unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info());
+ unsigned int dyn_r_type = (r_type == elfcpp::R_386_TLS_LE_32
+ ? elfcpp::R_386_TLS_TPOFF32
+ : elfcpp::R_386_TLS_TPOFF);
+ Reloc_section* rel_dyn = target->rel_dyn_section(layout);
+ rel_dyn->add_local(object, r_sym, dyn_r_type, output_section,
+ data_shndx, reloc.get_r_offset());
}
break;
case elfcpp::R_386_GOTOFF:
case elfcpp::R_386_GOT32:
{
- return true;
+ return true;
}
default:
return false;
inline void
Target_i386::Scan::global(Symbol_table* symtab,
- Layout* layout,
- Target_i386* target,
- Sized_relobj_file<32, false>* object,
- unsigned int data_shndx,
- Output_section* output_section,
- const elfcpp::Rel<32, false>& reloc,
- unsigned int r_type,
- Symbol* gsym)
+ Layout* layout,
+ Target_i386* target,
+ Sized_relobj_file<32, false>* object,
+ unsigned int data_shndx,
+ Output_section* output_section,
+ const elfcpp::Rel<32, false>& reloc,
+ unsigned int r_type,
+ Symbol* gsym)
{
// A STT_GNU_IFUNC symbol may require a PLT entry.
if (gsym->type() == elfcpp::STT_GNU_IFUNC
case elfcpp::R_386_16:
case elfcpp::R_386_8:
{
- // Make a PLT entry if necessary.
- if (gsym->needs_plt_entry())
- {
- target->make_plt_entry(symtab, layout, gsym);
- // Since this is not a PC-relative relocation, we may be
- // taking the address of a function. In that case we need to
- // set the entry in the dynamic symbol table to the address of
- // the PLT entry.
- if (gsym->is_from_dynobj() && !parameters->options().shared())
- gsym->set_needs_dynsym_value();
- }
- // Make a dynamic relocation if necessary.
- if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
- {
- if (gsym->may_need_copy_reloc())
- {
- target->copy_reloc(symtab, layout, object,
- data_shndx, output_section, gsym, reloc);
- }
+ // Make a PLT entry if necessary.
+ if (gsym->needs_plt_entry())
+ {
+ target->make_plt_entry(symtab, layout, gsym);
+ // Since this is not a PC-relative relocation, we may be
+ // taking the address of a function. In that case we need to
+ // set the entry in the dynamic symbol table to the address of
+ // the PLT entry.
+ if (gsym->is_from_dynobj() && !parameters->options().shared())
+ gsym->set_needs_dynsym_value();
+ }
+ // Make a dynamic relocation if necessary.
+ if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
+ {
+ if (gsym->may_need_copy_reloc())
+ {
+ target->copy_reloc(symtab, layout, object,
+ data_shndx, output_section, gsym, reloc);
+ }
else if (r_type == elfcpp::R_386_32
&& gsym->type() == elfcpp::STT_GNU_IFUNC
&& gsym->can_use_relative_reloc(false)
object, data_shndx,
reloc.get_r_offset());
}
- else if (r_type == elfcpp::R_386_32
- && gsym->can_use_relative_reloc(false))
- {
- Reloc_section* rel_dyn = target->rel_dyn_section(layout);
+ else if (r_type == elfcpp::R_386_32
+ && gsym->can_use_relative_reloc(false))
+ {
+ Reloc_section* rel_dyn = target->rel_dyn_section(layout);
rel_dyn->add_global_relative(gsym, elfcpp::R_386_RELATIVE,
output_section, object,
data_shndx, reloc.get_r_offset());
- }
- else
- {
- Reloc_section* rel_dyn = target->rel_dyn_section(layout);
- rel_dyn->add_global(gsym, r_type, output_section, object,
- data_shndx, reloc.get_r_offset());
- }
- }
+ }
+ else
+ {
+ Reloc_section* rel_dyn = target->rel_dyn_section(layout);
+ rel_dyn->add_global(gsym, r_type, output_section, object,
+ data_shndx, reloc.get_r_offset());
+ }
+ }
}
break;
case elfcpp::R_386_PC16:
case elfcpp::R_386_PC8:
{
- // Make a PLT entry if necessary.
- if (gsym->needs_plt_entry())
- {
- // These relocations are used for function calls only in
- // non-PIC code. For a 32-bit relocation in a shared library,
- // we'll need a text relocation anyway, so we can skip the
- // PLT entry and let the dynamic linker bind the call directly
- // to the target. For smaller relocations, we should use a
- // PLT entry to ensure that the call can reach.
- if (!parameters->options().shared()
- || r_type != elfcpp::R_386_PC32)
- target->make_plt_entry(symtab, layout, gsym);
- }
- // Make a dynamic relocation if necessary.
- if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
- {
- if (gsym->may_need_copy_reloc())
- {
- target->copy_reloc(symtab, layout, object,
- data_shndx, output_section, gsym, reloc);
- }
- else
- {
- Reloc_section* rel_dyn = target->rel_dyn_section(layout);
- rel_dyn->add_global(gsym, r_type, output_section, object,
- data_shndx, reloc.get_r_offset());
- }
- }
+ // Make a PLT entry if necessary.
+ if (gsym->needs_plt_entry())
+ {
+ // These relocations are used for function calls only in
+ // non-PIC code. For a 32-bit relocation in a shared library,
+ // we'll need a text relocation anyway, so we can skip the
+ // PLT entry and let the dynamic linker bind the call directly
+ // to the target. For smaller relocations, we should use a
+ // PLT entry to ensure that the call can reach.
+ if (!parameters->options().shared()
+ || r_type != elfcpp::R_386_PC32)
+ target->make_plt_entry(symtab, layout, gsym);
+ }
+ // Make a dynamic relocation if necessary.
+ if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
+ {
+ if (gsym->may_need_copy_reloc())
+ {
+ target->copy_reloc(symtab, layout, object,
+ data_shndx, output_section, gsym, reloc);
+ }
+ else
+ {
+ Reloc_section* rel_dyn = target->rel_dyn_section(layout);
+ rel_dyn->add_global(gsym, r_type, output_section, object,
+ data_shndx, reloc.get_r_offset());
+ }
+ }
}
break;
case elfcpp::R_386_GOT32:
{
- // The symbol requires a GOT entry.
- Output_data_got<32, false>* got = target->got_section(symtab, layout);
- if (gsym->final_value_is_known())
+ // The symbol requires a GOT entry.
+ Output_data_got<32, false>* got = target->got_section(symtab, layout);
+ if (gsym->final_value_is_known())
{
// For a STT_GNU_IFUNC symbol we want the PLT address.
if (gsym->type() == elfcpp::STT_GNU_IFUNC)
else
got->add_global(gsym, GOT_TYPE_STANDARD);
}
- else
- {
- // If this symbol is not fully resolved, we need to add a
- // GOT entry with a dynamic relocation.
- Reloc_section* rel_dyn = target->rel_dyn_section(layout);
+ else
+ {
+ // If this symbol is not fully resolved, we need to add a
+ // GOT entry with a dynamic relocation.
+ Reloc_section* rel_dyn = target->rel_dyn_section(layout);
// Use a GLOB_DAT rather than a RELATIVE reloc if:
//
//
// 3) This is a STT_GNU_IFUNC symbol in position dependent
// code, again so that function address comparisons work.
- if (gsym->is_from_dynobj()
- || gsym->is_undefined()
- || gsym->is_preemptible()
+ if (gsym->is_from_dynobj()
+ || gsym->is_undefined()
+ || gsym->is_preemptible()
|| (gsym->visibility() == elfcpp::STV_PROTECTED
&& parameters->options().shared())
|| (gsym->type() == elfcpp::STT_GNU_IFUNC
&& parameters->options().output_is_position_independent()))
- got->add_global_with_rel(gsym, GOT_TYPE_STANDARD,
- rel_dyn, elfcpp::R_386_GLOB_DAT);
- else
- {
+ got->add_global_with_rel(gsym, GOT_TYPE_STANDARD,
+ rel_dyn, elfcpp::R_386_GLOB_DAT);
+ else
+ {
// For a STT_GNU_IFUNC symbol we want to write the PLT
// offset into the GOT, so that function pointer
// comparisons work correctly.
&& !parameters->options().shared())
gsym->set_needs_dynsym_value();
}
- if (is_new)
+ if (is_new)
{
unsigned int got_off = gsym->got_offset(GOT_TYPE_STANDARD);
rel_dyn->add_global_relative(gsym, elfcpp::R_386_RELATIVE,
got, got_off);
}
- }
- }
+ }
+ }
}
break;
// if the symbol is defined in the output file and is protected
// or hidden.
if (gsym->is_defined()
- && !gsym->is_from_dynobj()
- && !gsym->is_preemptible())
+ && !gsym->is_from_dynobj()
+ && !gsym->is_preemptible())
break;
target->make_plt_entry(symtab, layout, gsym);
break;
{
const bool is_final = gsym->final_value_is_known();
const tls::Tls_optimization optimized_type
- = Target_i386::optimize_tls_reloc(is_final, r_type);
+ = Target_i386::optimize_tls_reloc(is_final, r_type);
switch (r_type)
{
case elfcpp::R_386_TLS_GD: // Global-dynamic
if (optimized_type == tls::TLSOPT_NONE)
{
- // Create a pair of GOT entries for the module index and
- // dtv-relative offset.
- Output_data_got<32, false>* got
- = target->got_section(symtab, layout);
- got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_PAIR,
- target->rel_dyn_section(layout),
- elfcpp::R_386_TLS_DTPMOD32,
- elfcpp::R_386_TLS_DTPOFF32);
+ // Create a pair of GOT entries for the module index and
+ // dtv-relative offset.
+ Output_data_got<32, false>* got
+ = target->got_section(symtab, layout);
+ got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_PAIR,
+ target->rel_dyn_section(layout),
+ elfcpp::R_386_TLS_DTPMOD32,
+ elfcpp::R_386_TLS_DTPOFF32);
}
else if (optimized_type == tls::TLSOPT_TO_IE)
{
- // Create a GOT entry for the tp-relative offset.
- Output_data_got<32, false>* got
- = target->got_section(symtab, layout);
- got->add_global_with_rel(gsym, GOT_TYPE_TLS_NOFFSET,
- target->rel_dyn_section(layout),
- elfcpp::R_386_TLS_TPOFF);
+ // Create a GOT entry for the tp-relative offset.
+ Output_data_got<32, false>* got
+ = target->got_section(symtab, layout);
+ got->add_global_with_rel(gsym, GOT_TYPE_TLS_NOFFSET,
+ target->rel_dyn_section(layout),
+ elfcpp::R_386_TLS_TPOFF);
}
else if (optimized_type != tls::TLSOPT_TO_LE)
unsupported_reloc_global(object, r_type, gsym);
case elfcpp::R_386_TLS_GOTDESC: // Global-dynamic (~oliva url)
target->define_tls_base_symbol(symtab, layout);
- if (optimized_type == tls::TLSOPT_NONE)
- {
- // Create a double GOT entry with an R_386_TLS_DESC
- // reloc. The R_386_TLS_DESC reloc is resolved
- // lazily, so the GOT entry needs to be in an area in
- // .got.plt, not .got. Call got_section to make sure
- // the section has been created.
+ if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Create a double GOT entry with an R_386_TLS_DESC
+ // reloc. The R_386_TLS_DESC reloc is resolved
+ // lazily, so the GOT entry needs to be in an area in
+ // .got.plt, not .got. Call got_section to make sure
+ // the section has been created.
target->got_section(symtab, layout);
- Output_data_got<32, false>* got = target->got_tlsdesc_section();
+ Output_data_got<32, false>* got = target->got_tlsdesc_section();
Reloc_section* rt = target->rel_tls_desc_section(layout);
- got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_DESC, rt,
- elfcpp::R_386_TLS_DESC, 0);
- }
- else if (optimized_type == tls::TLSOPT_TO_IE)
- {
- // Create a GOT entry for the tp-relative offset.
- Output_data_got<32, false>* got
- = target->got_section(symtab, layout);
- got->add_global_with_rel(gsym, GOT_TYPE_TLS_NOFFSET,
- target->rel_dyn_section(layout),
- elfcpp::R_386_TLS_TPOFF);
- }
- else if (optimized_type != tls::TLSOPT_TO_LE)
- unsupported_reloc_global(object, r_type, gsym);
+ got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_DESC, rt,
+ elfcpp::R_386_TLS_DESC, 0);
+ }
+ else if (optimized_type == tls::TLSOPT_TO_IE)
+ {
+ // Create a GOT entry for the tp-relative offset.
+ Output_data_got<32, false>* got
+ = target->got_section(symtab, layout);
+ got->add_global_with_rel(gsym, GOT_TYPE_TLS_NOFFSET,
+ target->rel_dyn_section(layout),
+ elfcpp::R_386_TLS_TPOFF);
+ }
+ else if (optimized_type != tls::TLSOPT_TO_LE)
+ unsupported_reloc_global(object, r_type, gsym);
break;
case elfcpp::R_386_TLS_DESC_CALL:
case elfcpp::R_386_TLS_LDM: // Local-dynamic
if (optimized_type == tls::TLSOPT_NONE)
{
- // Create a GOT entry for the module index.
- target->got_mod_index_entry(symtab, layout, object);
+ // Create a GOT entry for the module index.
+ target->got_mod_index_entry(symtab, layout, object);
}
else if (optimized_type != tls::TLSOPT_TO_LE)
unsupported_reloc_global(object, r_type, gsym);
layout->set_has_static_tls();
if (optimized_type == tls::TLSOPT_NONE)
{
- // For the R_386_TLS_IE relocation, we need to create a
- // dynamic relocation when building a shared library.
- if (r_type == elfcpp::R_386_TLS_IE
- && parameters->options().shared())
- {
- Reloc_section* rel_dyn = target->rel_dyn_section(layout);
- rel_dyn->add_global_relative(gsym, elfcpp::R_386_RELATIVE,
- output_section, object,
- data_shndx,
- reloc.get_r_offset());
- }
- // Create a GOT entry for the tp-relative offset.
- Output_data_got<32, false>* got
- = target->got_section(symtab, layout);
- unsigned int dyn_r_type = (r_type == elfcpp::R_386_TLS_IE_32
- ? elfcpp::R_386_TLS_TPOFF32
- : elfcpp::R_386_TLS_TPOFF);
- unsigned int got_type = (r_type == elfcpp::R_386_TLS_IE_32
- ? GOT_TYPE_TLS_OFFSET
- : GOT_TYPE_TLS_NOFFSET);
- got->add_global_with_rel(gsym, got_type,
- target->rel_dyn_section(layout),
- dyn_r_type);
+ // For the R_386_TLS_IE relocation, we need to create a
+ // dynamic relocation when building a shared library.
+ if (r_type == elfcpp::R_386_TLS_IE
+ && parameters->options().shared())
+ {
+ Reloc_section* rel_dyn = target->rel_dyn_section(layout);
+ rel_dyn->add_global_relative(gsym, elfcpp::R_386_RELATIVE,
+ output_section, object,
+ data_shndx,
+ reloc.get_r_offset());
+ }
+ // Create a GOT entry for the tp-relative offset.
+ Output_data_got<32, false>* got
+ = target->got_section(symtab, layout);
+ unsigned int dyn_r_type = (r_type == elfcpp::R_386_TLS_IE_32
+ ? elfcpp::R_386_TLS_TPOFF32
+ : elfcpp::R_386_TLS_TPOFF);
+ unsigned int got_type = (r_type == elfcpp::R_386_TLS_IE_32
+ ? GOT_TYPE_TLS_OFFSET
+ : GOT_TYPE_TLS_NOFFSET);
+ got->add_global_with_rel(gsym, got_type,
+ target->rel_dyn_section(layout),
+ dyn_r_type);
}
else if (optimized_type != tls::TLSOPT_TO_LE)
unsupported_reloc_global(object, r_type, gsym);
layout->set_has_static_tls();
if (parameters->options().shared())
{
- // We need to create a dynamic relocation.
- unsigned int dyn_r_type = (r_type == elfcpp::R_386_TLS_LE_32
- ? elfcpp::R_386_TLS_TPOFF32
- : elfcpp::R_386_TLS_TPOFF);
- Reloc_section* rel_dyn = target->rel_dyn_section(layout);
- rel_dyn->add_global(gsym, dyn_r_type, output_section, object,
- data_shndx, reloc.get_r_offset());
+ // We need to create a dynamic relocation.
+ unsigned int dyn_r_type = (r_type == elfcpp::R_386_TLS_LE_32
+ ? elfcpp::R_386_TLS_TPOFF32
+ : elfcpp::R_386_TLS_TPOFF);
+ Reloc_section* rel_dyn = target->rel_dyn_section(layout);
+ rel_dyn->add_global(gsym, dyn_r_type, output_section, object,
+ data_shndx, reloc.get_r_offset());
}
break;
void
Target_i386::gc_process_relocs(Symbol_table* symtab,
- Layout* layout,
- Sized_relobj_file<32, false>* object,
- unsigned int data_shndx,
- unsigned int,
- const unsigned char* prelocs,
- size_t reloc_count,
- Output_section* output_section,
- bool needs_special_offset_handling,
- size_t local_symbol_count,
- const unsigned char* plocal_symbols)
+ Layout* layout,
+ Sized_relobj_file<32, false>* object,
+ unsigned int data_shndx,
+ unsigned int,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols)
{
gold::gc_process_relocs<32, false, Target_i386, elfcpp::SHT_REL,
- Target_i386::Scan,
- Target_i386::Relocatable_size_for_reloc>(
+ Target_i386::Scan,
+ Target_i386::Relocatable_size_for_reloc>(
symtab,
layout,
this,
void
Target_i386::scan_relocs(Symbol_table* symtab,
- Layout* layout,
- Sized_relobj_file<32, false>* object,
- unsigned int data_shndx,
- unsigned int sh_type,
- const unsigned char* prelocs,
- size_t reloc_count,
- Output_section* output_section,
- bool needs_special_offset_handling,
- size_t local_symbol_count,
- const unsigned char* plocal_symbols)
+ Layout* layout,
+ Sized_relobj_file<32, false>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols)
{
if (sh_type == elfcpp::SHT_RELA)
{
inline bool
Target_i386::Relocate::should_apply_static_reloc(const Sized_symbol<32>* gsym,
- unsigned int r_type,
- bool is_32bit,
+ unsigned int r_type,
+ bool is_32bit,
Output_section* output_section)
{
// If the output section is not allocated, then we didn't call
// (c) the relocation is not 32 bits wide.
if (gsym == NULL)
return !(parameters->options().output_is_position_independent()
- && (ref_flags & Symbol::ABSOLUTE_REF)
- && !is_32bit);
+ && (ref_flags & Symbol::ABSOLUTE_REF)
+ && !is_32bit);
// For global symbols, we use the same helper routines used in the
// scan pass. If we did not create a dynamic relocation, or if we
// relocation.
bool has_dyn = gsym->needs_dynamic_reloc(ref_flags);
bool is_rel = (ref_flags & Symbol::ABSOLUTE_REF)
- && gsym->can_use_relative_reloc(ref_flags
- & Symbol::FUNCTION_CALL);
+ && gsym->can_use_relative_reloc(ref_flags
+ & Symbol::FUNCTION_CALL);
return !has_dyn || is_rel;
}
inline bool
Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo,
- Target_i386* target,
- Output_section* output_section,
- size_t relnum,
- const elfcpp::Rel<32, false>& rel,
- unsigned int r_type,
- const Sized_symbol<32>* gsym,
- const Symbol_value<32>* psymval,
- unsigned char* view,
- elfcpp::Elf_types<32>::Elf_Addr address,
- section_size_type view_size)
+ Target_i386* target,
+ Output_section* output_section,
+ size_t relnum,
+ const elfcpp::Rel<32, false>& rel,
+ unsigned int r_type,
+ const Sized_symbol<32>* gsym,
+ const Symbol_value<32>* psymval,
+ unsigned char* view,
+ elfcpp::Elf_types<32>::Elf_Addr address,
+ section_size_type view_size)
{
if (this->skip_call_tls_get_addr_)
{
if ((r_type != elfcpp::R_386_PLT32
- && r_type != elfcpp::R_386_PC32)
+ && r_type != elfcpp::R_386_PC32)
|| gsym == NULL
|| strcmp(gsym->name(), "___tls_get_addr") != 0)
gold_error_at_location(relinfo, relnum, rel.get_r_offset(),
{
case elfcpp::R_386_GOT32:
if (gsym != NULL)
- {
- gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD));
- got_offset = (gsym->got_offset(GOT_TYPE_STANDARD)
- - target->got_size());
- }
+ {
+ gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD));
+ got_offset = (gsym->got_offset(GOT_TYPE_STANDARD)
+ - target->got_size());
+ }
else
- {
- unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
- gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD));
- got_offset = (object->local_got_offset(r_sym, GOT_TYPE_STANDARD)
- - target->got_size());
- }
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
+ gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD));
+ got_offset = (object->local_got_offset(r_sym, GOT_TYPE_STANDARD)
+ - target->got_size());
+ }
have_got_offset = true;
break;
case elfcpp::R_386_32:
if (should_apply_static_reloc(gsym, r_type, true, output_section))
- Relocate_functions<32, false>::rel32(view, object, psymval);
+ Relocate_functions<32, false>::rel32(view, object, psymval);
break;
case elfcpp::R_386_PC32:
if (should_apply_static_reloc(gsym, r_type, true, output_section))
- Relocate_functions<32, false>::pcrel32(view, object, psymval, address);
+ Relocate_functions<32, false>::pcrel32(view, object, psymval, address);
break;
case elfcpp::R_386_16:
if (should_apply_static_reloc(gsym, r_type, false, output_section))
- Relocate_functions<32, false>::rel16(view, object, psymval);
+ Relocate_functions<32, false>::rel16(view, object, psymval);
break;
case elfcpp::R_386_PC16:
if (should_apply_static_reloc(gsym, r_type, false, output_section))
- Relocate_functions<32, false>::pcrel16(view, object, psymval, address);
+ Relocate_functions<32, false>::pcrel16(view, object, psymval, address);
break;
case elfcpp::R_386_8:
if (should_apply_static_reloc(gsym, r_type, false, output_section))
- Relocate_functions<32, false>::rel8(view, object, psymval);
+ Relocate_functions<32, false>::rel8(view, object, psymval);
break;
case elfcpp::R_386_PC8:
if (should_apply_static_reloc(gsym, r_type, false, output_section))
- Relocate_functions<32, false>::pcrel8(view, object, psymval, address);
+ Relocate_functions<32, false>::pcrel8(view, object, psymval, address);
break;
case elfcpp::R_386_PLT32:
case elfcpp::R_386_TLS_LE: // Local-exec
case elfcpp::R_386_TLS_LE_32:
this->relocate_tls(relinfo, target, relnum, rel, r_type, gsym, psymval,
- view, address, view_size);
+ view, address, view_size);
break;
case elfcpp::R_386_32PLT:
inline void
Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo,
- Target_i386* target,
+ Target_i386* target,
size_t relnum,
const elfcpp::Rel<32, false>& rel,
unsigned int r_type,
break;
}
else
- {
- unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE
- ? GOT_TYPE_TLS_NOFFSET
- : GOT_TYPE_TLS_PAIR);
- unsigned int got_offset;
- if (gsym != NULL)
- {
- gold_assert(gsym->has_got_offset(got_type));
- got_offset = gsym->got_offset(got_type) - target->got_size();
- }
- else
- {
- unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
- gold_assert(object->local_has_got_offset(r_sym, got_type));
- got_offset = (object->local_got_offset(r_sym, got_type)
+ {
+ unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE
+ ? GOT_TYPE_TLS_NOFFSET
+ : GOT_TYPE_TLS_PAIR);
+ unsigned int got_offset;
+ if (gsym != NULL)
+ {
+ gold_assert(gsym->has_got_offset(got_type));
+ got_offset = gsym->got_offset(got_type) - target->got_size();
+ }
+ else
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
+ gold_assert(object->local_has_got_offset(r_sym, got_type));
+ got_offset = (object->local_got_offset(r_sym, got_type)
- target->got_size());
- }
- if (optimized_type == tls::TLSOPT_TO_IE)
+ }
+ if (optimized_type == tls::TLSOPT_TO_IE)
{
this->tls_gd_to_ie(relinfo, relnum, tls_segment, rel, r_type,
- got_offset, view, view_size);
- break;
+ got_offset, view, view_size);
+ break;
+ }
+ else if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Relocate the field with the offset of the pair of GOT
+ // entries.
+ Relocate_functions<32, false>::rel32(view, got_offset);
+ break;
}
- else if (optimized_type == tls::TLSOPT_NONE)
- {
- // Relocate the field with the offset of the pair of GOT
- // entries.
- Relocate_functions<32, false>::rel32(view, got_offset);
- break;
- }
- }
+ }
gold_error_at_location(relinfo, relnum, rel.get_r_offset(),
_("unsupported reloc %u"),
r_type);
case elfcpp::R_386_TLS_DESC_CALL:
this->local_dynamic_type_ = LOCAL_DYNAMIC_GNU;
if (optimized_type == tls::TLSOPT_TO_LE)
- {
+ {
if (tls_segment == NULL)
{
gold_assert(parameters->errors()->error_count() > 0
return;
}
this->tls_desc_gd_to_le(relinfo, relnum, tls_segment,
- rel, r_type, value, view,
- view_size);
+ rel, r_type, value, view,
+ view_size);
break;
- }
+ }
else
- {
- unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE
- ? GOT_TYPE_TLS_NOFFSET
- : GOT_TYPE_TLS_DESC);
- unsigned int got_offset = 0;
+ {
+ unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE
+ ? GOT_TYPE_TLS_NOFFSET
+ : GOT_TYPE_TLS_DESC);
+ unsigned int got_offset = 0;
if (r_type == elfcpp::R_386_TLS_GOTDESC
&& optimized_type == tls::TLSOPT_NONE)
{
got_offset = (target->got_size()
+ target->got_plt_section()->data_size());
}
- if (gsym != NULL)
- {
- gold_assert(gsym->has_got_offset(got_type));
- got_offset += gsym->got_offset(got_type) - target->got_size();
- }
- else
- {
- unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
- gold_assert(object->local_has_got_offset(r_sym, got_type));
- got_offset += (object->local_got_offset(r_sym, got_type)
+ if (gsym != NULL)
+ {
+ gold_assert(gsym->has_got_offset(got_type));
+ got_offset += gsym->got_offset(got_type) - target->got_size();
+ }
+ else
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
+ gold_assert(object->local_has_got_offset(r_sym, got_type));
+ got_offset += (object->local_got_offset(r_sym, got_type)
- target->got_size());
- }
- if (optimized_type == tls::TLSOPT_TO_IE)
+ }
+ if (optimized_type == tls::TLSOPT_TO_IE)
{
if (tls_segment == NULL)
{
return;
}
this->tls_desc_gd_to_ie(relinfo, relnum, tls_segment, rel, r_type,
- got_offset, view, view_size);
- break;
+ got_offset, view, view_size);
+ break;
+ }
+ else if (optimized_type == tls::TLSOPT_NONE)
+ {
+ if (r_type == elfcpp::R_386_TLS_GOTDESC)
+ {
+ // Relocate the field with the offset of the pair of GOT
+ // entries.
+ Relocate_functions<32, false>::rel32(view, got_offset);
+ }
+ break;
}
- else if (optimized_type == tls::TLSOPT_NONE)
- {
- if (r_type == elfcpp::R_386_TLS_GOTDESC)
- {
- // Relocate the field with the offset of the pair of GOT
- // entries.
- Relocate_functions<32, false>::rel32(view, got_offset);
- }
- break;
- }
- }
+ }
gold_error_at_location(relinfo, relnum, rel.get_r_offset(),
_("unsupported reloc %u"),
r_type);
break;
}
else if (optimized_type == tls::TLSOPT_NONE)
- {
- // Relocate the field with the offset of the GOT entry for
- // the module index.
- unsigned int got_offset;
- got_offset = (target->got_mod_index_entry(NULL, NULL, NULL)
+ {
+ // Relocate the field with the offset of the GOT entry for
+ // the module index.
+ unsigned int got_offset;
+ got_offset = (target->got_mod_index_entry(NULL, NULL, NULL)
- target->got_size());
- Relocate_functions<32, false>::rel32(view, got_offset);
- break;
- }
+ Relocate_functions<32, false>::rel32(view, got_offset);
+ break;
+ }
gold_error_at_location(relinfo, relnum, rel.get_r_offset(),
_("unsupported reloc %u"),
r_type);
break;
}
else if (optimized_type == tls::TLSOPT_NONE)
- {
- // Relocate the field with the offset of the GOT entry for
- // the tp-relative offset of the symbol.
+ {
+ // Relocate the field with the offset of the GOT entry for
+ // the tp-relative offset of the symbol.
unsigned int got_type = (r_type == elfcpp::R_386_TLS_IE_32
- ? GOT_TYPE_TLS_OFFSET
- : GOT_TYPE_TLS_NOFFSET);
- unsigned int got_offset;
- if (gsym != NULL)
- {
- gold_assert(gsym->has_got_offset(got_type));
- got_offset = gsym->got_offset(got_type);
- }
- else
- {
- unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
- gold_assert(object->local_has_got_offset(r_sym, got_type));
- got_offset = object->local_got_offset(r_sym, got_type);
- }
- // For the R_386_TLS_IE relocation, we need to apply the
- // absolute address of the GOT entry.
- if (r_type == elfcpp::R_386_TLS_IE)
- got_offset += target->got_plt_section()->address();
- // All GOT offsets are relative to the end of the GOT.
- got_offset -= target->got_size();
- Relocate_functions<32, false>::rel32(view, got_offset);
- break;
- }
+ ? GOT_TYPE_TLS_OFFSET
+ : GOT_TYPE_TLS_NOFFSET);
+ unsigned int got_offset;
+ if (gsym != NULL)
+ {
+ gold_assert(gsym->has_got_offset(got_type));
+ got_offset = gsym->got_offset(got_type);
+ }
+ else
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info());
+ gold_assert(object->local_has_got_offset(r_sym, got_type));
+ got_offset = object->local_got_offset(r_sym, got_type);
+ }
+ // For the R_386_TLS_IE relocation, we need to apply the
+ // absolute address of the GOT entry.
+ if (r_type == elfcpp::R_386_TLS_IE)
+ got_offset += target->got_plt_section()->address();
+ // All GOT offsets are relative to the end of the GOT.
+ got_offset -= target->got_size();
+ Relocate_functions<32, false>::rel32(view, got_offset);
+ break;
+ }
gold_error_at_location(relinfo, relnum, rel.get_r_offset(),
_("unsupported reloc %u"),
r_type);
// If we're creating a shared library, a dynamic relocation will
// have been created for this location, so do not apply it now.
if (!parameters->options().shared())
- {
+ {
if (tls_segment == NULL)
{
gold_assert(parameters->errors()->error_count() > 0
|| issue_undefined_symbol_error(gsym));
return;
}
- value -= tls_segment->memsz();
- Relocate_functions<32, false>::rel32(view, value);
- }
+ value -= tls_segment->memsz();
+ Relocate_functions<32, false>::rel32(view, value);
+ }
break;
case elfcpp::R_386_TLS_LE_32:
// If we're creating a shared library, a dynamic relocation will
// have been created for this location, so do not apply it now.
if (!parameters->options().shared())
- {
+ {
if (tls_segment == NULL)
{
gold_assert(parameters->errors()->error_count() > 0
|| issue_undefined_symbol_error(gsym));
return;
}
- value = tls_segment->memsz() - value;
- Relocate_functions<32, false>::rel32(view, value);
- }
+ value = tls_segment->memsz() - value;
+ Relocate_functions<32, false>::rel32(view, value);
+ }
break;
}
}
unsigned char op2 = view[-2];
tls::check_tls(relinfo, relnum, rel.get_r_offset(),
- op2 == 0x8d || op2 == 0x04);
+ op2 == 0x8d || op2 == 0x04);
tls::check_tls(relinfo, relnum, rel.get_r_offset(), view[4] == 0xe8);
int roff = 5;
tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, -3);
tls::check_tls(relinfo, relnum, rel.get_r_offset(), view[-3] == 0x8d);
tls::check_tls(relinfo, relnum, rel.get_r_offset(),
- ((op1 & 0xc7) == 0x05 && op1 != (4 << 3)));
+ ((op1 & 0xc7) == 0x05 && op1 != (4 << 3)));
memcpy(view - 3, "\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12);
}
else
{
tls::check_tls(relinfo, relnum, rel.get_r_offset(),
- (op1 & 0xf8) == 0x80 && (op1 & 7) != 4);
+ (op1 & 0xf8) == 0x80 && (op1 & 7) != 4);
if (rel.get_r_offset() + 9 < view_size
- && view[9] == 0x90)
+ && view[9] == 0x90)
{
// There is a trailing nop. Use the size byte subl.
memcpy(view - 2, "\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12);
unsigned char op2 = view[-2];
tls::check_tls(relinfo, relnum, rel.get_r_offset(),
- op2 == 0x8d || op2 == 0x04);
+ op2 == 0x8d || op2 == 0x04);
tls::check_tls(relinfo, relnum, rel.get_r_offset(), view[4] == 0xe8);
int roff = 5;
tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, -3);
tls::check_tls(relinfo, relnum, rel.get_r_offset(), view[-3] == 0x8d);
tls::check_tls(relinfo, relnum, rel.get_r_offset(),
- ((op1 & 0xc7) == 0x05 && op1 != (4 << 3)));
+ ((op1 & 0xc7) == 0x05 && op1 != (4 << 3)));
memcpy(view - 3, "\x65\xa1\0\0\0\0\x03\x83\0\0\0", 12);
}
else
{
tls::check_tls(relinfo, relnum, rel.get_r_offset(),
- (op1 & 0xf8) == 0x80 && (op1 & 7) != 4);
+ (op1 & 0xf8) == 0x80 && (op1 & 7) != 4);
if (rel.get_r_offset() + 9 < view_size
- && view[9] == 0x90)
+ && view[9] == 0x90)
{
- // FIXME: This is not the right instruction sequence.
+ // FIXME: This is not the right instruction sequence.
// There is a trailing nop. Use the size byte subl.
memcpy(view - 2, "\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12);
roff = 6;
}
else
{
- // FIXME: This is not the right instruction sequence.
+ // FIXME: This is not the right instruction sequence.
// Use the five byte subl.
memcpy(view - 2, "\x65\xa1\0\0\0\0\x2d\0\0\0", 11);
}
tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, -2);
tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, 4);
tls::check_tls(relinfo, relnum, rel.get_r_offset(),
- view[-2] == 0x8d && view[-1] == 0x83);
+ view[-2] == 0x8d && view[-1] == 0x83);
view[-1] = 0x05;
value -= tls_segment->memsz();
Relocate_functions<32, false>::rel32(view, value);
gold_assert(r_type == elfcpp::R_386_TLS_DESC_CALL);
tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, 2);
tls::check_tls(relinfo, relnum, rel.get_r_offset(),
- view[0] == 0xff && view[1] == 0x10);
+ view[0] == 0xff && view[1] == 0x10);
view[0] = 0x66;
view[1] = 0x90;
}
tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, -2);
tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, 4);
tls::check_tls(relinfo, relnum, rel.get_r_offset(),
- view[-2] == 0x8d && view[-1] == 0x83);
+ view[-2] == 0x8d && view[-1] == 0x83);
view[-2] = 0x8b;
Relocate_functions<32, false>::rel32(view, value);
}
gold_assert(r_type == elfcpp::R_386_TLS_DESC_CALL);
tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, 2);
tls::check_tls(relinfo, relnum, rel.get_r_offset(),
- view[0] == 0xff && view[1] == 0x10);
+ view[0] == 0xff && view[1] == 0x10);
view[0] = 0x66;
view[1] = 0x90;
}
// FIXME: Does this test really always pass?
tls::check_tls(relinfo, relnum, rel.get_r_offset(),
- view[-2] == 0x8d && view[-1] == 0x83);
+ view[-2] == 0x8d && view[-1] == 0x83);
tls::check_tls(relinfo, relnum, rel.get_r_offset(), view[4] == 0xe8);
{
// movl XX,%reg ==> movl $YY,%reg
tls::check_tls(relinfo, relnum, rel.get_r_offset(),
- (op1 & 0xc7) == 0x05);
+ (op1 & 0xc7) == 0x05);
view[-2] = 0xc7;
view[-1] = 0xc0 | ((op1 >> 3) & 7);
}
{
// addl XX,%reg ==> addl $YY,%reg
tls::check_tls(relinfo, relnum, rel.get_r_offset(),
- (op1 & 0xc7) == 0x05);
+ (op1 & 0xc7) == 0x05);
view[-2] = 0x81;
view[-1] = 0xc0 | ((op1 >> 3) & 7);
}
unsigned char op1 = view[-1];
unsigned char op2 = view[-2];
tls::check_tls(relinfo, relnum, rel.get_r_offset(),
- (op1 & 0xc0) == 0x80 && (op1 & 7) != 4);
+ (op1 & 0xc0) == 0x80 && (op1 & 7) != 4);
if (op2 == 0x8b)
{
// movl %gs:XX(%reg1),%reg2 ==> movl $YY,%reg2
jmp[0] = 0xe9;
elfcpp::Swap_unaligned<32, false>::writeval(jmp + 1, length - 5);
return (std::string(reinterpret_cast<char*>(&jmp[0]), 5)
- + std::string(length - 5, static_cast<char>(0x90)));
+ + std::string(length - 5, static_cast<char>(0x90)));
}
// Nop sequences of various lengths.
const char nop4[4] = { '\x8d', '\x74', '\x26', // leal 0(%esi,1),%esi
'\x00'};
const char nop5[5] = { '\x90', '\x8d', '\x74', // nop
- '\x26', '\x00' }; // leal 0(%esi,1),%esi
+ '\x26', '\x00' }; // leal 0(%esi,1),%esi
const char nop6[6] = { '\x8d', '\xb6', '\x00', // leal 0L(%esi),%esi
- '\x00', '\x00', '\x00' };
+ '\x00', '\x00', '\x00' };
const char nop7[7] = { '\x8d', '\xb4', '\x26', // leal 0L(%esi,1),%esi
- '\x00', '\x00', '\x00',
+ '\x00', '\x00', '\x00',
'\x00' };
const char nop8[8] = { '\x90', '\x8d', '\xb4', // nop
- '\x26', '\x00', '\x00', // leal 0L(%esi,1),%esi
+ '\x26', '\x00', '\x00', // leal 0L(%esi,1),%esi
'\x00', '\x00' };
const char nop9[9] = { '\x89', '\xf6', '\x8d', // movl %esi,%esi
- '\xbc', '\x27', '\x00', // leal 0L(%edi,1),%edi
+ '\xbc', '\x27', '\x00', // leal 0L(%edi,1),%edi
'\x00', '\x00', '\x00' };
const char nop10[10] = { '\x8d', '\x76', '\x00', // leal 0(%esi),%esi
- '\x8d', '\xbc', '\x27', // leal 0L(%edi,1),%edi
+ '\x8d', '\xbc', '\x27', // leal 0L(%edi,1),%edi
'\x00', '\x00', '\x00',
'\x00' };
const char nop11[11] = { '\x8d', '\x74', '\x26', // leal 0(%esi,1),%esi
- '\x00', '\x8d', '\xbc', // leal 0L(%edi,1),%edi
+ '\x00', '\x8d', '\xbc', // leal 0L(%edi,1),%edi
'\x27', '\x00', '\x00',
'\x00', '\x00' };
const char nop12[12] = { '\x8d', '\xb6', '\x00', // leal 0L(%esi),%esi
- '\x00', '\x00', '\x00', // leal 0L(%edi),%edi
+ '\x00', '\x00', '\x00', // leal 0L(%edi),%edi
'\x8d', '\xbf', '\x00',
'\x00', '\x00', '\x00' };
const char nop13[13] = { '\x8d', '\xb6', '\x00', // leal 0L(%esi),%esi
- '\x00', '\x00', '\x00', // leal 0L(%edi,1),%edi
+ '\x00', '\x00', '\x00', // leal 0L(%edi,1),%edi
'\x8d', '\xbc', '\x27',
'\x00', '\x00', '\x00',
- '\x00' };
+ '\x00' };
const char nop14[14] = { '\x8d', '\xb4', '\x26', // leal 0L(%esi,1),%esi
- '\x00', '\x00', '\x00', // leal 0L(%edi,1),%edi
+ '\x00', '\x00', '\x00', // leal 0L(%edi,1),%edi
'\x00', '\x8d', '\xbc',
'\x27', '\x00', '\x00',
- '\x00', '\x00' };
+ '\x00', '\x00' };
const char nop15[15] = { '\xeb', '\x0d', '\x90', // jmp .+15
- '\x90', '\x90', '\x90', // nop,nop,nop,...
+ '\x90', '\x90', '\x90', // nop,nop,nop,...
'\x90', '\x90', '\x90',
'\x90', '\x90', '\x90',
- '\x90', '\x90', '\x90' };
+ '\x90', '\x90', '\x90' };
const char* nops[16] = {
NULL,
void
Target_i386::do_calls_non_split(Relobj* object, unsigned int shndx,
- section_offset_type fnoffset,
- section_size_type fnsize,
- unsigned char* view,
- section_size_type view_size,
- std::string* from,
- std::string* to) const
+ section_offset_type fnoffset,
+ section_size_type fnsize,
+ unsigned char* view,
+ section_size_type view_size,
+ std::string* from,
+ std::string* to) const
{
// The function starts with a comparison of the stack pointer and a
// field in the TCB. This is followed by a jump.
*to = "__morestack_non_split";
}
-// The selector for i386 object files.
+// The selector for i386 object files. Note this is never instantiated
+// directly. It's only used in Target_selector_i386_nacl, below.
class Target_selector_i386 : public Target_selector_freebsd
{
{ return new Target_i386(); }
};
-Target_selector_i386 target_selector_i386;
+// NaCl variant. It uses different PLT contents.
+
+class Output_data_plt_i386_nacl : public Output_data_plt_i386
+{
+ public:
+ Output_data_plt_i386_nacl(Layout* layout,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ : Output_data_plt_i386(layout, plt_entry_size, got_plt, got_irelative)
+ { }
+
+ protected:
+ virtual unsigned int
+ do_get_plt_entry_size() const
+ { return plt_entry_size; }
+
+ virtual void
+ do_add_eh_frame(Layout* layout)
+ {
+ layout->add_eh_frame_for_plt(this, plt_eh_frame_cie, plt_eh_frame_cie_size,
+ plt_eh_frame_fde, plt_eh_frame_fde_size);
+ }
+
+ // The size of an entry in the PLT.
+ static const int plt_entry_size = 64;
+
+ // The .eh_frame unwind information for the PLT.
+ static const int plt_eh_frame_fde_size = 32;
+ static const unsigned char plt_eh_frame_fde[plt_eh_frame_fde_size];
+};
+
+class Output_data_plt_i386_nacl_exec : public Output_data_plt_i386_nacl
+{
+public:
+ Output_data_plt_i386_nacl_exec(Layout* layout,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ : Output_data_plt_i386_nacl(layout, got_plt, got_irelative)
+ { }
+
+ protected:
+ virtual void
+ do_fill_first_plt_entry(unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr got_address);
+
+ virtual unsigned int
+ do_fill_plt_entry(unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr got_address,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_rel_offset);
+
+ private:
+ // The first entry in the PLT for an executable.
+ static const unsigned char first_plt_entry[plt_entry_size];
+
+ // Other entries in the PLT for an executable.
+ static const unsigned char plt_entry[plt_entry_size];
+};
+
+class Output_data_plt_i386_nacl_dyn : public Output_data_plt_i386_nacl
+{
+ public:
+ Output_data_plt_i386_nacl_dyn(Layout* layout,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ : Output_data_plt_i386_nacl(layout, got_plt, got_irelative)
+ { }
+
+ protected:
+ virtual void
+ do_fill_first_plt_entry(unsigned char* pov, elfcpp::Elf_types<32>::Elf_Addr);
+
+ virtual unsigned int
+ do_fill_plt_entry(unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_rel_offset);
+
+ private:
+ // The first entry in the PLT for a shared object.
+ static const unsigned char first_plt_entry[plt_entry_size];
+
+ // Other entries in the PLT for a shared object.
+ static const unsigned char plt_entry[plt_entry_size];
+};
+
+class Target_i386_nacl : public Target_i386
+{
+ public:
+ Target_i386_nacl()
+ : Target_i386(&i386_nacl_info)
+ { }
+
+ protected:
+ virtual Output_data_plt_i386*
+ do_make_data_plt(Layout* layout,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative,
+ bool dyn)
+ {
+ if (dyn)
+ return new Output_data_plt_i386_nacl_dyn(layout, got_plt, got_irelative);
+ else
+ return new Output_data_plt_i386_nacl_exec(layout, got_plt, got_irelative);
+ }
+
+ private:
+ static const Target::Target_info i386_nacl_info;
+};
+
+const Target::Target_info Target_i386_nacl::i386_nacl_info =
+{
+ 32, // size
+ false, // is_big_endian
+ elfcpp::EM_386, // machine_code
+ false, // has_make_symbol
+ false, // has_resolve
+ true, // has_code_fill
+ true, // is_default_stack_executable
+ true, // can_icf_inline_merge_sections
+ '\0', // wrap_char
+ "/lib/ld-nacl-x86-32.so.1", // dynamic_linker
+ 0x20000, // default_text_segment_address
+ 0x10000, // abi_pagesize (overridable by -z max-page-size)
+ 0x10000, // common_pagesize (overridable by -z common-page-size)
+ true, // isolate_execinstr
+ 0x10000000, // rosegment_gap
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_UNDEF, // large_common_shndx
+ 0, // small_common_section_flags
+ 0, // large_common_section_flags
+ NULL, // attributes_section
+ NULL // attributes_vendor
+};
+
+#define NACLMASK 0xe0 // 32-byte alignment mask
+
+const unsigned char
+Output_data_plt_i386_nacl_exec::first_plt_entry[plt_entry_size] =
+{
+ 0xff, 0x35, // pushl contents of memory address
+ 0, 0, 0, 0, // replaced with address of .got + 4
+ 0x8b, 0x0d, // movl contents of address, %ecx
+ 0, 0, 0, 0, // replaced with address of .got + 8
+ 0x83, 0xe1, NACLMASK, // andl $NACLMASK, %ecx
+ 0xff, 0xe1, // jmp *%ecx
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90
+};
+
+void
+Output_data_plt_i386_nacl_exec::do_fill_first_plt_entry(
+ unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr got_address)
+{
+ memcpy(pov, first_plt_entry, plt_entry_size);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 2, got_address + 4);
+ elfcpp::Swap<32, false>::writeval(pov + 8, got_address + 8);
+}
+
+// The first entry in the PLT for a shared object.
+
+const unsigned char
+Output_data_plt_i386_nacl_dyn::first_plt_entry[plt_entry_size] =
+{
+ 0xff, 0xb3, 4, 0, 0, 0, // pushl 4(%ebx)
+ 0x8b, 0x4b, 0x08, // mov 0x8(%ebx), %ecx
+ 0x83, 0xe1, NACLMASK, // andl $NACLMASK, %ecx
+ 0xff, 0xe1, // jmp *%ecx
+ 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90, // nops
+ 0x90, 0x90, 0x90, 0x90, 0x90 // nops
+};
+
+void
+Output_data_plt_i386_nacl_dyn::do_fill_first_plt_entry(
+ unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr)
+{
+ memcpy(pov, first_plt_entry, plt_entry_size);
+}
+
+// Subsequent entries in the PLT for an executable.
+
+const unsigned char
+Output_data_plt_i386_nacl_exec::plt_entry[plt_entry_size] =
+{
+ 0x8b, 0x0d, // movl contents of address, %ecx */
+ 0, 0, 0, 0, // replaced with address of symbol in .got
+ 0x83, 0xe1, NACLMASK, // andl $NACLMASK, %ecx
+ 0xff, 0xe1, // jmp *%ecx
+
+ // Pad to the next 32-byte boundary with nop instructions.
+ 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+
+ // Lazy GOT entries point here (32-byte aligned).
+ 0x68, // pushl immediate
+ 0, 0, 0, 0, // replaced with offset into relocation table
+ 0xe9, // jmp relative
+ 0, 0, 0, 0, // replaced with offset to start of .plt
+
+ // Pad to the next 32-byte boundary with nop instructions.
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90
+};
+
+unsigned int
+Output_data_plt_i386_nacl_exec::do_fill_plt_entry(
+ unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr got_address,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_rel_offset)
+{
+ memcpy(pov, plt_entry, plt_entry_size);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
+ got_address + got_offset);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 33, plt_rel_offset);
+ elfcpp::Swap<32, false>::writeval(pov + 38, - (plt_offset + 38 + 4));
+ return 32;
+}
+
+// Subsequent entries in the PLT for a shared object.
+
+const unsigned char
+Output_data_plt_i386_nacl_dyn::plt_entry[plt_entry_size] =
+{
+ 0x8b, 0x8b, // movl offset(%ebx), %ecx
+ 0, 0, 0, 0, // replaced with offset of symbol in .got
+ 0x83, 0xe1, 0xe0, // andl $NACLMASK, %ecx
+ 0xff, 0xe1, // jmp *%ecx
+
+ // Pad to the next 32-byte boundary with nop instructions.
+ 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+
+ // Lazy GOT entries point here (32-byte aligned).
+ 0x68, // pushl immediate
+ 0, 0, 0, 0, // replaced with offset into relocation table.
+ 0xe9, // jmp relative
+ 0, 0, 0, 0, // replaced with offset to start of .plt.
+
+ // Pad to the next 32-byte boundary with nop instructions.
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90,
+ 0x90, 0x90
+};
+
+unsigned int
+Output_data_plt_i386_nacl_dyn::do_fill_plt_entry(
+ unsigned char* pov,
+ elfcpp::Elf_types<32>::Elf_Addr,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_rel_offset)
+{
+ memcpy(pov, plt_entry, plt_entry_size);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 2, got_offset);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 33, plt_rel_offset);
+ elfcpp::Swap<32, false>::writeval(pov + 38, - (plt_offset + 38 + 4));
+ return 32;
+}
+
+const unsigned char
+Output_data_plt_i386_nacl::plt_eh_frame_fde[plt_eh_frame_fde_size] =
+{
+ 0, 0, 0, 0, // Replaced with offset to .plt.
+ 0, 0, 0, 0, // Replaced with size of .plt.
+ 0, // Augmentation size.
+ elfcpp::DW_CFA_def_cfa_offset, 8, // DW_CFA_def_cfa_offset: 8.
+ elfcpp::DW_CFA_advance_loc + 6, // Advance 6 to __PLT__ + 6.
+ elfcpp::DW_CFA_def_cfa_offset, 12, // DW_CFA_def_cfa_offset: 12.
+ elfcpp::DW_CFA_advance_loc + 58, // Advance 58 to __PLT__ + 64.
+ elfcpp::DW_CFA_def_cfa_expression, // DW_CFA_def_cfa_expression.
+ 13, // Block length.
+ elfcpp::DW_OP_breg4, 4, // Push %esp + 4.
+ elfcpp::DW_OP_breg8, 0, // Push %eip.
+ elfcpp::DW_OP_const1u, 63, // Push 0x3f.
+ elfcpp::DW_OP_and, // & (%eip & 0x3f).
+ elfcpp::DW_OP_const1u, 37, // Push 0x25.
+ elfcpp::DW_OP_ge, // >= ((%eip & 0x3f) >= 0x25)
+ elfcpp::DW_OP_lit2, // Push 2.
+ elfcpp::DW_OP_shl, // << (((%eip & 0x3f) >= 0x25) << 2)
+ elfcpp::DW_OP_plus, // + ((((%eip&0x3f)>=0x25)<<2)+%esp+4
+ elfcpp::DW_CFA_nop, // Align to 32 bytes.
+ elfcpp::DW_CFA_nop
+};
+
+// The selector for i386-nacl object files.
+
+class Target_selector_i386_nacl
+ : public Target_selector_nacl<Target_selector_i386, Target_i386_nacl>
+{
+ public:
+ Target_selector_i386_nacl()
+ : Target_selector_nacl<Target_selector_i386,
+ Target_i386_nacl>("x86-32",
+ "elf32-i386-nacl",
+ "elf_i386_nacl")
+ { }
+};
+
+Target_selector_i386_nacl target_selector_i386;
} // End anonymous namespace.
// inremental.cc -- incremental linking support for gold
-// Copyright 2009, 2010, 2011 Free Software Foundation, Inc.
+// Copyright 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
// Written by Mikolaj Zalewski <mikolajz@google.com>.
// This file is part of gold.
if (vasprintf(&buf, format, args) < 0)
gold_nomem();
gold_info(_("the link might take longer: "
- "cannot perform incremental link: %s"), buf);
+ "cannot perform incremental link: %s"), buf);
free(buf);
}
unsigned int main_strtab_shndx =
this->elf_file_.section_link(main_symtab_shndx);
gold_assert(main_strtab_shndx != elfcpp::SHN_UNDEF
- && main_strtab_shndx < this->elf_file_.shnum());
+ && main_strtab_shndx < this->elf_file_.shnum());
this->main_strtab_loc_ = this->elf_file_.section_contents(main_strtab_shndx);
// Walk the list of input files (a) to setup an Input_reader for each
case INCREMENTAL_INPUT_ARCHIVE:
{
Incremental_library* lib =
- new Incremental_library(input_file.filename(), i,
+ new Incremental_library(input_file.filename(), i,
&this->input_entry_readers_[i]);
this->library_map_[i] = lib;
unsigned int member_count = input_file.get_member_count();
check_input_args(input_args_map, lib->begin(), lib->end());
}
else
- {
- gold_assert(p->is_file());
- unsigned int arg_serial = p->file().arg_serial();
- if (arg_serial > 0)
+ {
+ gold_assert(p->is_file());
+ unsigned int arg_serial = p->file().arg_serial();
+ if (arg_serial > 0)
{
gold_assert(arg_serial <= input_args_map.size());
gold_assert(input_args_map[arg_serial - 1] == 0);
input_args_map[arg_serial - 1] = &*p;
}
- }
+ }
}
}
if (incremental_inputs->command_line() != inputs.command_line())
{
gold_debug(DEBUG_INCREMENTAL,
- "old command line: %s",
- inputs.command_line());
+ "old command line: %s",
+ inputs.command_line());
gold_debug(DEBUG_INCREMENTAL,
- "new command line: %s",
- incremental_inputs->command_line().c_str());
+ "new command line: %s",
+ incremental_inputs->command_line().c_str());
explain_no_incremental(_("command line changed"));
return false;
}
Shdr shdr(pshdr);
const char* name;
if (!shstrtab.get_c_string(shdr.get_sh_name(), &name))
- name = NULL;
+ name = NULL;
gold_debug(DEBUG_INCREMENTAL,
"Output section: %2d %08lx %08lx %08lx %3d %s",
- i,
- static_cast<long>(shdr.get_sh_addr()),
- static_cast<long>(shdr.get_sh_offset()),
- static_cast<long>(shdr.get_sh_size()),
- shdr.get_sh_type(), name ? name : "<null>");
+ i,
+ static_cast<long>(shdr.get_sh_addr()),
+ static_cast<long>(shdr.get_sh_offset()),
+ static_cast<long>(shdr.get_sh_size()),
+ shdr.get_sh_type(), name ? name : "<null>");
this->section_map_[i] = layout->init_fixed_output_section(name, shdr);
pshdr += shdr_size;
}
{
bool is_def;
bool is_copy;
- unsigned int output_symndx =
+ unsigned int output_symndx =
input_file.get_output_symbol_index(i, &is_def, &is_copy);
if (is_copy)
{
elfcpp::Sym<size, big_endian> gsym(sym_p);
unsigned int shndx = gsym.get_st_shndx();
if (shndx < 1 || shndx >= this->section_map_.size())
- continue;
+ continue;
Output_section* os = this->section_map_[shndx];
off_t offset = gsym.get_st_value() - os->address();
os->reserve(offset, gsym.get_st_size());
for (unsigned int i = 0; i < shnum; i++)
{
typename Input_entry_reader::Input_section_info sect =
- input_file.get_input_section(i);
+ input_file.get_input_section(i);
if (sect.output_shndx == 0 || sect.sh_offset == -1)
- continue;
+ continue;
Output_section* os = this->section_map_[sect.output_shndx];
gold_assert(os != NULL);
os->reserve(sect.sh_offset, sect.sh_size);
// output file.
unsigned int offset = isymtab.get_list_head(i);
while (offset > 0)
- {
+ {
Incremental_global_symbol_reader<big_endian> sym_info =
this->inputs_reader().global_symbol_reader_at_offset(offset);
unsigned int r_base = sym_info.reloc_offset();
view_size);
gold_debug(DEBUG_INCREMENTAL,
- " %08lx: %s + %d: type %d addend %ld",
- (long)(section_offset + r_offset),
- os->name(),
- (int)r_offset,
- r_type,
- (long)r_addend);
+ " %08lx: %s + %d: type %d addend %ld",
+ (long)(section_offset + r_offset),
+ os->name(),
+ (int)r_offset,
+ r_type,
+ (long)r_addend);
target->apply_relocation(&relinfo, r_offset, r_type, r_addend,
gsym, view, address, view_size);
of->write_output_view(section_offset, view_size, view);
}
offset = sym_info.next_offset();
- }
+ }
}
}
template<int size, bool big_endian>
Incremental_binary*
make_sized_incremental_binary(Output_file* file,
- const elfcpp::Ehdr<size, big_endian>& ehdr)
+ const elfcpp::Ehdr<size, big_endian>& ehdr)
{
- Target* target = select_target(ehdr.get_e_machine(), size, big_endian,
- ehdr.get_e_ident()[elfcpp::EI_OSABI],
- ehdr.get_e_ident()[elfcpp::EI_ABIVERSION]);
+ Target* target = select_target(NULL, 0, // XXX
+ ehdr.get_e_machine(), size, big_endian,
+ ehdr.get_e_ident()[elfcpp::EI_OSABI],
+ ehdr.get_e_ident()[elfcpp::EI_ABIVERSION]);
if (target == NULL)
{
explain_no_incremental(_("unsupported ELF machine number %d"),
- ehdr.get_e_machine());
+ ehdr.get_e_machine());
return NULL;
}
bool big_endian = false;
std::string error;
if (!elfcpp::Elf_recognizer::is_valid_header(p, want, &size, &big_endian,
- &error))
+ &error))
{
explain_no_incremental(error.c_str());
return NULL;
if (size == 32)
{
if (big_endian)
- {
+ {
#ifdef HAVE_TARGET_32_BIG
- result = make_sized_incremental_binary<32, true>(
- file, elfcpp::Ehdr<32, true>(p));
+ result = make_sized_incremental_binary<32, true>(
+ file, elfcpp::Ehdr<32, true>(p));
#else
- explain_no_incremental(_("unsupported file: 32-bit, big-endian"));
+ explain_no_incremental(_("unsupported file: 32-bit, big-endian"));
#endif
- }
+ }
else
- {
+ {
#ifdef HAVE_TARGET_32_LITTLE
- result = make_sized_incremental_binary<32, false>(
- file, elfcpp::Ehdr<32, false>(p));
+ result = make_sized_incremental_binary<32, false>(
+ file, elfcpp::Ehdr<32, false>(p));
#else
- explain_no_incremental(_("unsupported file: 32-bit, little-endian"));
+ explain_no_incremental(_("unsupported file: 32-bit, little-endian"));
#endif
- }
+ }
}
else if (size == 64)
{
if (big_endian)
- {
+ {
#ifdef HAVE_TARGET_64_BIG
- result = make_sized_incremental_binary<64, true>(
- file, elfcpp::Ehdr<64, true>(p));
+ result = make_sized_incremental_binary<64, true>(
+ file, elfcpp::Ehdr<64, true>(p));
#else
- explain_no_incremental(_("unsupported file: 64-bit, big-endian"));
+ explain_no_incremental(_("unsupported file: 64-bit, big-endian"));
#endif
- }
+ }
else
- {
+ {
#ifdef HAVE_TARGET_64_LITTLE
- result = make_sized_incremental_binary<64, false>(
- file, elfcpp::Ehdr<64, false>(p));
+ result = make_sized_incremental_binary<64, false>(
+ file, elfcpp::Ehdr<64, false>(p));
#else
- explain_no_incremental(_("unsupported file: 64-bit, little-endian"));
+ explain_no_incremental(_("unsupported file: 64-bit, little-endian"));
#endif
- }
+ }
}
else
gold_unreachable();
|| is_prefix_of("--incremental-base=", argv[i])
|| is_prefix_of("--incremental-patch=", argv[i])
|| is_prefix_of("--debug=", argv[i]))
- continue;
+ continue;
if (strcmp(argv[i], "--incremental-base") == 0
|| strcmp(argv[i], "--incremental-patch") == 0
|| strcmp(argv[i], "--debug") == 0)
// Now append argv[i], but with all single-quotes escaped
const char* argpos = argv[i];
while (1)
- {
- const int len = strcspn(argpos, "'");
- args.append(argpos, len);
- if (argpos[len] == '\0')
- break;
- args.append("'\"'\"'");
- argpos += len + 1;
- }
+ {
+ const int len = strcspn(argpos, "'");
+ args.append(argpos, len);
+ if (argpos[len] == '\0')
+ break;
+ args.append("'\"'\"'");
+ argpos += len + 1;
+ }
args.append("'");
}
this->command_line_ = args;
this->strtab_->add(this->command_line_.c_str(), false,
- &this->command_line_key_);
+ &this->command_line_key_);
}
// Record the input archive file ARCHIVE. This is called by the
if (!obj->is_dynamic())
{
this->current_object_entry_ =
- new Incremental_object_entry(filename_key, obj, arg_serial, mtime);
+ new Incremental_object_entry(filename_key, obj, arg_serial, mtime);
input_entry = this->current_object_entry_;
if (arch != NULL)
{
#ifdef HAVE_TARGET_32_LITTLE
case Parameters::TARGET_32_LITTLE:
this->inputs_section_ =
- new Output_section_incremental_inputs<32, false>(this, symtab);
+ new Output_section_incremental_inputs<32, false>(this, symtab);
reloc_align = 4;
break;
#endif
#ifdef HAVE_TARGET_32_BIG
case Parameters::TARGET_32_BIG:
this->inputs_section_ =
- new Output_section_incremental_inputs<32, true>(this, symtab);
+ new Output_section_incremental_inputs<32, true>(this, symtab);
reloc_align = 4;
break;
#endif
#ifdef HAVE_TARGET_64_LITTLE
case Parameters::TARGET_64_LITTLE:
this->inputs_section_ =
- new Output_section_incremental_inputs<64, false>(this, symtab);
+ new Output_section_incremental_inputs<64, false>(this, symtab);
reloc_align = 8;
break;
#endif
#ifdef HAVE_TARGET_64_BIG
case Parameters::TARGET_64_BIG:
this->inputs_section_ =
- new Output_section_incremental_inputs<64, true>(this, symtab);
+ new Output_section_incremental_inputs<64, true>(this, symtab);
reloc_align = 8;
break;
#endif
continue;
if (sym->is_forwarder())
sym = this->symtab_->resolve_forwards(sym);
- if (sym->symtab_index() != -1U)
- ++nsyms_out;
+ if (sym->symtab_index() != -1U)
+ ++nsyms_out;
}
info_offset += nsyms_out * 4;
}
{
gold_assert(static_cast<unsigned int>(pov - oview) == (*p)->get_offset());
section_offset_type filename_offset =
- strtab->get_offset_from_key((*p)->get_filename_key());
+ strtab->get_offset_from_key((*p)->get_filename_key());
const Timespec& mtime = (*p)->get_mtime();
unsigned int flags = (*p)->type();
if ((*p)->is_in_system_directory())
- flags |= INCREMENTAL_INPUT_IN_SYSTEM_DIR;
+ flags |= INCREMENTAL_INPUT_IN_SYSTEM_DIR;
if ((*p)->as_needed())
- flags |= INCREMENTAL_INPUT_AS_NEEDED;
+ flags |= INCREMENTAL_INPUT_AS_NEEDED;
Swap32::writeval(pov, filename_offset);
Swap32::writeval(pov + 4, (*p)->get_info_offset());
Swap64::writeval(pov + 8, mtime.seconds);
// but exclude linker-predefined symbols and symbols
// copied from shared objects.
if (!sym->is_predefined()
- && !sym->is_copied_from_dynobj())
+ && !sym->is_copied_from_dynobj())
shndx = -1U;
}
else if (sym->object() == obj && sym->is_defined())
continue;
if (sym->is_forwarder())
sym = this->symtab_->resolve_forwards(sym);
- if (sym->symtab_index() == -1U)
- continue;
+ if (sym->symtab_index() == -1U)
+ continue;
unsigned int flags = 0;
// If the symbol has hidden or internal visibility, we
// mark it as defined in the shared object so we don't
const Got_offset_list* got_offsets = sym->got_offset_list();
if (got_offsets != NULL)
{
- this->info_.sym_index = sym->symtab_index();
- this->info_.input_index = 0;
- Got_visitor v(this->info_);
+ this->info_.sym_index = sym->symtab_index();
+ this->info_.input_index = 0;
+ Got_visitor v(this->info_);
got_offsets->for_all_got_offsets(&v);
}
if (sym->has_plt_offset())
for (unsigned int i = 1; i < shnum; i++)
{
typename Input_entry_reader::Input_section_info sect =
- this->input_reader_.get_input_section(i - 1);
+ this->input_reader_.get_input_section(i - 1);
// Add the section to the incremental inputs layout.
incremental_inputs->report_input_section(this, i, sect.name,
sect.sh_size);
if (sect.output_shndx == 0 || sect.sh_offset == -1)
- continue;
+ continue;
Output_section* os = this->ibase_->output_section(sect.output_shndx);
gold_assert(os != NULL);
out_sections[i] = os;
{
const char* signature = this->input_reader_.get_comdat_group_signature(i);
if (signature == NULL || signature[0] == '\0')
- this->error(_("COMDAT group has no signature"));
+ this->error(_("COMDAT group has no signature"));
bool keep = layout->find_or_add_kept_section(signature, this, i, true,
true, NULL);
if (keep)
incremental_inputs->report_comdat_group(this, signature);
else
- this->error(_("COMDAT group %s included twice in incremental link"),
+ this->error(_("COMDAT group %s included twice in incremental link"),
signature);
}
// Local hidden symbols start out as globals, but get converted to
// to local during output.
if (st_bind == elfcpp::STB_LOCAL)
- st_bind = elfcpp::STB_GLOBAL;
+ st_bind = elfcpp::STB_GLOBAL;
unsigned int input_shndx = info.shndx();
if (input_shndx == 0 || input_shndx == -1U)
Symbol* res = symtab->add_from_incrobj(this, name, NULL, &sym);
if (shndx != elfcpp::SHN_UNDEF)
- ++this->defined_count_;
+ ++this->defined_count_;
// If this is a linker-defined symbol that hasn't yet been defined,
// define it now.
elfcpp::Sym<size, big_endian> sym(symp);
const char* name;
if (!strtab.get_c_string(sym.get_st_name(), &name))
- name = "";
+ name = "";
gold_debug(DEBUG_INCREMENTAL, "Local symbol %d: %s", i, name);
name = pool->add(name, true, NULL);
this->local_symbols_.push_back(Local_symbol(name,
unsigned char* dyn_oview = NULL;
if (dyn_output_size > 0)
dyn_oview = of->get_output_view(this->local_dynsym_offset_,
- dyn_output_size);
+ dyn_output_size);
// Write the local symbols.
unsigned char* ov = oview;
// Write the symbol to the output dynamic symbol table.
if (lsym.needs_dynsym_entry)
- {
- gold_assert(dyn_ov < dyn_oview + dyn_output_size);
- elfcpp::Sym_write<size, big_endian> osym(dyn_ov);
- osym.put_st_name(dynpool->get_offset(lsym.name));
- osym.put_st_value(lsym.st_value);
- osym.put_st_size(lsym.st_size);
+ {
+ gold_assert(dyn_ov < dyn_oview + dyn_output_size);
+ elfcpp::Sym_write<size, big_endian> osym(dyn_ov);
+ osym.put_st_name(dynpool->get_offset(lsym.name));
+ osym.put_st_value(lsym.st_value);
+ osym.put_st_size(lsym.st_size);
osym.put_st_info(elfcpp::STB_LOCAL,
static_cast<elfcpp::STT>(lsym.st_type));
- osym.put_st_other(0);
- osym.put_st_shndx(st_shndx);
- dyn_ov += sym_size;
- }
+ osym.put_st_other(0);
+ osym.put_st_shndx(st_shndx);
+ dyn_ov += sym_size;
+ }
}
if (output_size > 0)
{
gold_assert(dyn_ov - dyn_oview == dyn_output_size);
of->write_output_view(this->local_dynsym_offset_, dyn_output_size,
- dyn_oview);
+ dyn_oview);
}
}
// Local hidden symbols start out as globals, but get converted to
// to local during output.
if (st_bind == elfcpp::STB_LOCAL)
- st_bind = elfcpp::STB_GLOBAL;
+ st_bind = elfcpp::STB_GLOBAL;
if (!is_def)
{
// layout.cc -- lay out output file sections for gold
-// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012
+// Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
Free_list::allocate(off_t len, uint64_t align, off_t minoff)
{
gold_debug(DEBUG_INCREMENTAL,
- "Free_list::allocate(%08lx, %d, %08lx)",
- static_cast<long>(len), static_cast<int>(align),
- static_cast<long>(minoff));
+ "Free_list::allocate(%08lx, %d, %08lx)",
+ static_cast<long>(len), static_cast<int>(align),
+ static_cast<long>(minoff));
if (len == 0)
return align_address(minoff, align);
Free_list::print_stats()
{
fprintf(stderr, _("%s: total free lists: %u\n"),
- program_name, Free_list::num_lists);
+ program_name, Free_list::num_lists);
fprintf(stderr, _("%s: total free list nodes: %u\n"),
- program_name, Free_list::num_nodes);
+ program_name, Free_list::num_nodes);
fprintf(stderr, _("%s: calls to Free_list::remove: %u\n"),
- program_name, Free_list::num_removes);
+ program_name, Free_list::num_removes);
fprintf(stderr, _("%s: nodes visited: %u\n"),
- program_name, Free_list::num_remove_visits);
+ program_name, Free_list::num_remove_visits);
fprintf(stderr, _("%s: calls to Free_list::allocate: %u\n"),
- program_name, Free_list::num_allocates);
+ program_name, Free_list::num_allocates);
fprintf(stderr, _("%s: nodes visited: %u\n"),
- program_name, Free_list::num_allocate_visits);
+ program_name, Free_list::num_allocate_visits);
}
// Layout::Relaxation_debug_check methods.
++p)
gold_assert((*p)->address_and_file_offset_have_reset_values());
}
-
+
// Save information of SECTIONS for checking later.
void
Layout* layout = this->layout_;
off_t file_size = layout->finalize(this->input_objects_,
this->symtab_,
- this->target_,
+ this->target_,
task);
// Now we know the final size of the output file and we know where
// incremental information from the file before (possibly)
// overwriting it.
if (parameters->incremental_update())
- layout->incremental_base()->apply_incremental_relocs(this->symtab_,
- this->layout_,
+ layout->incremental_base()->apply_incremental_relocs(this->symtab_,
+ this->layout_,
of);
of->resize(file_size);
{
// Debugging sections can only be recognized by name.
if (is_prefix_of(".debug", name)
- && !is_lines_only_debug_section(name))
+ && !is_lines_only_debug_section(name))
return false;
}
if (parameters->options().strip_debug_gdb()
{
// Debugging sections can only be recognized by name.
if (is_prefix_of(".debug", name)
- && !is_gdb_debug_section(name))
+ && !is_gdb_debug_section(name))
return false;
}
if (parameters->options().strip_lto_sections()
- && !parameters->options().relocatable()
- && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0)
- {
- // Ignore LTO sections containing intermediate code.
- if (is_prefix_of(".gnu.lto_", name))
- return false;
- }
+ && !parameters->options().relocatable()
+ && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0)
+ {
+ // Ignore LTO sections containing intermediate code.
+ if (is_prefix_of(".gnu.lto_", name))
+ return false;
+ }
// The GNU linker strips .gnu_debuglink sections, so we do too.
// This is a feature used to keep debugging information in
// separate files.
if (lookup_type == elfcpp::SHT_PROGBITS)
{
- if (flags == 0)
- {
- Output_section* same_name = this->find_output_section(name);
- if (same_name != NULL
- && (same_name->type() == elfcpp::SHT_PROGBITS
+ if (flags == 0)
+ {
+ Output_section* same_name = this->find_output_section(name);
+ if (same_name != NULL
+ && (same_name->type() == elfcpp::SHT_PROGBITS
|| same_name->type() == elfcpp::SHT_INIT_ARRAY
|| same_name->type() == elfcpp::SHT_FINI_ARRAY
|| same_name->type() == elfcpp::SHT_PREINIT_ARRAY)
- && (same_name->flags() & elfcpp::SHF_TLS) == 0)
- os = same_name;
- }
- else if ((flags & elfcpp::SHF_TLS) == 0)
- {
- elfcpp::Elf_Xword zero_flags = 0;
- const Key zero_key(name_key, std::make_pair(lookup_type,
+ && (same_name->flags() & elfcpp::SHF_TLS) == 0)
+ os = same_name;
+ }
+ else if ((flags & elfcpp::SHF_TLS) == 0)
+ {
+ elfcpp::Elf_Xword zero_flags = 0;
+ const Key zero_key(name_key, std::make_pair(lookup_type,
zero_flags));
- Section_name_map::iterator p =
- this->section_name_map_.find(zero_key);
- if (p != this->section_name_map_.end())
+ Section_name_map::iterator p =
+ this->section_name_map_.find(zero_key);
+ if (p != this->section_name_map_.end())
os = p->second;
- }
+ }
}
if (os == NULL)
Stringpool::Key name_key;
name = this->namepool_.add(name, true, &name_key);
Output_section* os = this->get_output_section(name, name_key, sh_type,
- sh_flags, ORDER_INVALID, false);
+ sh_flags, ORDER_INVALID, false);
os->set_fixed_layout(sh_addr, sh_offset, sh_size, sh_addralign);
if (sh_type != elfcpp::SHT_NOBITS)
this->free_list_.remove(sh_offset, sh_offset + sh_size);
false, ORDER_INVALID,
false);
if (os == NULL)
- return;
+ return;
this->gdb_index_data_ = new Gdb_index(os);
os->add_output_section_data(this->gdb_index_data_);
os = new Output_compressed_section(¶meters->options(), name, type,
flags);
else if ((flags & elfcpp::SHF_ALLOC) == 0
- && parameters->options().strip_debug_non_line()
- && strcmp(".debug_abbrev", name) == 0)
+ && parameters->options().strip_debug_non_line()
+ && strcmp(".debug_abbrev", name) == 0)
{
os = this->debug_abbrev_ = new Output_reduced_debug_abbrev_section(
- name, type, flags);
+ name, type, flags);
if (this->debug_info_)
- this->debug_info_->set_abbreviations(this->debug_abbrev_);
+ this->debug_info_->set_abbreviations(this->debug_abbrev_);
}
else if ((flags & elfcpp::SHF_ALLOC) == 0
- && parameters->options().strip_debug_non_line()
- && strcmp(".debug_info", name) == 0)
+ && parameters->options().strip_debug_non_line()
+ && strcmp(".debug_info", name) == 0)
{
os = this->debug_info_ = new Output_reduced_debug_info_section(
- name, type, flags);
+ name, type, flags);
if (this->debug_abbrev_)
- this->debug_info_->set_abbreviations(this->debug_abbrev_);
+ this->debug_info_->set_abbreviations(this->debug_abbrev_);
}
else
{
// a minimum size, so we must prevent allocations from the
// free list that leave a hole smaller than the minimum.
if (strcmp(name, ".debug_info") == 0)
- os->set_free_space_fill(new Output_fill_debug_info(false));
+ os->set_free_space_fill(new Output_fill_debug_info(false));
else if (strcmp(name, ".debug_types") == 0)
- os->set_free_space_fill(new Output_fill_debug_info(true));
+ os->set_free_space_fill(new Output_fill_debug_info(true));
else if (strcmp(name, ".debug_line") == 0)
- os->set_free_space_fill(new Output_fill_debug_line());
+ os->set_free_space_fill(new Output_fill_debug_line());
}
// If we have already attached the sections to segments, then we
// need to attach this one now. This happens for sections created
// directly by the linker.
if (this->sections_are_attached_)
- this->attach_section_to_segment(os);
+ this->attach_section_to_segment(¶meters->target(), os);
return os;
}
// seen all the input sections.
void
-Layout::attach_sections_to_segments()
+Layout::attach_sections_to_segments(const Target* target)
{
for (Section_list::iterator p = this->section_list_.begin();
p != this->section_list_.end();
++p)
- this->attach_section_to_segment(*p);
+ this->attach_section_to_segment(target, *p);
this->sections_are_attached_ = true;
}
// Attach an output section to a segment.
void
-Layout::attach_section_to_segment(Output_section* os)
+Layout::attach_section_to_segment(const Target* target, Output_section* os)
{
if ((os->flags() & elfcpp::SHF_ALLOC) == 0)
this->unattached_section_list_.push_back(os);
else
- this->attach_allocated_section_to_segment(os);
+ this->attach_allocated_section_to_segment(target, os);
}
// Attach an allocated output section to a segment.
void
-Layout::attach_allocated_section_to_segment(Output_section* os)
+Layout::attach_allocated_section_to_segment(const Target* target,
+ Output_section* os)
{
elfcpp::Elf_Xword flags = os->flags();
gold_assert((flags & elfcpp::SHF_ALLOC) != 0);
if (!parameters->options().omagic()
&& ((*p)->flags() & elfcpp::PF_W) != (seg_flags & elfcpp::PF_W))
continue;
- if (parameters->options().rosegment()
- && ((*p)->flags() & elfcpp::PF_X) != (seg_flags & elfcpp::PF_X))
- continue;
+ if ((target->isolate_execinstr() || parameters->options().rosegment())
+ && ((*p)->flags() & elfcpp::PF_X) != (seg_flags & elfcpp::PF_X))
+ continue;
// If -Tbss was specified, we need to separate the data and BSS
// segments.
if (parameters->options().user_set_Tbss())
if (p == this->segment_list_.end())
{
Output_segment* oseg = this->make_output_segment(elfcpp::PT_LOAD,
- seg_flags);
+ seg_flags);
if (os->is_large_data_section())
oseg->set_is_large_data_segment();
oseg->add_output_section_to_load(this, os, seg_flags);
{
// See if we already have an equivalent PT_NOTE segment.
for (p = this->segment_list_.begin();
- p != segment_list_.end();
- ++p)
- {
- if ((*p)->type() == elfcpp::PT_NOTE
- && (((*p)->flags() & elfcpp::PF_W)
- == (seg_flags & elfcpp::PF_W)))
- {
- (*p)->add_output_section_to_nonload(os, seg_flags);
- break;
- }
- }
+ p != segment_list_.end();
+ ++p)
+ {
+ if ((*p)->type() == elfcpp::PT_NOTE
+ && (((*p)->flags() & elfcpp::PF_W)
+ == (seg_flags & elfcpp::PF_W)))
+ {
+ (*p)->add_output_section_to_nonload(os, seg_flags);
+ break;
+ }
+ }
if (p == this->segment_list_.end())
- {
- Output_segment* oseg = this->make_output_segment(elfcpp::PT_NOTE,
- seg_flags);
- oseg->add_output_section_to_nonload(os, seg_flags);
- }
+ {
+ Output_segment* oseg = this->make_output_segment(elfcpp::PT_NOTE,
+ seg_flags);
+ oseg->add_output_section_to_nonload(os, seg_flags);
+ }
}
// If we see a loadable SHF_TLS section, we create a PT_TLS
{
const std::string name_string(name);
const std::string start_name(cident_section_start_prefix
- + name_string);
+ + name_string);
const std::string stop_name(cident_section_stop_prefix
- + name_string);
+ + name_string);
symtab->define_in_output_data(start_name.c_str(),
NULL, // version
// necessary.
Output_segment*
-Layout::find_first_load_seg()
+Layout::find_first_load_seg(const Target* target)
{
Output_segment* best = NULL;
for (Segment_list::const_iterator p = this->segment_list_.begin();
if ((*p)->type() == elfcpp::PT_LOAD
&& ((*p)->flags() & elfcpp::PF_R) != 0
&& (parameters->options().omagic()
- || ((*p)->flags() & elfcpp::PF_W) == 0))
- {
- if (best == NULL || this->segment_precedes(*p, best))
- best = *p;
- }
+ || ((*p)->flags() & elfcpp::PF_W) == 0)
+ && (!target->isolate_execinstr()
+ || ((*p)->flags() & elfcpp::PF_X) == 0))
+ {
+ if (best == NULL || this->segment_precedes(*p, best))
+ best = *p;
+ }
}
if (best != NULL)
return best;
this->relro_segment_ = segment;
++list_iter;
- }
+ }
else
{
- list_iter = this->segment_list_.erase(list_iter);
+ list_iter = this->segment_list_.erase(list_iter);
// This is a segment created during section layout. It should be
// safe to remove it since we should have removed all pointers to it.
delete segment;
(*p)->reset_address_and_file_offset();
}
-
+
// Reset special output object address and file offsets.
for (Data_list::iterator p = this->special_output_list_.begin();
p != this->special_output_list_.end();
p != this->script_output_section_data_list_.end();
++p)
delete *p;
- this->script_output_section_data_list_.clear();
+ this->script_output_section_data_list_.clear();
}
// Prepare for relaxation.
if (is_debugging_enabled(DEBUG_RELAXATION))
this->relaxation_debug_check_->check_output_data_for_reset_values(
- this->section_list_, this->special_output_list_);
+ this->section_list_, this->special_output_list_);
// Also enable recording of output section data from scripts.
this->record_output_section_data_from_script_ = true;
// Relaxation loop body: If target has no relaxation, this runs only once
// Otherwise, the target relaxation hook is called at the end of
// each iteration. If the hook returns true, it means re-layout of
-// section is required.
+// section is required.
//
// The number of segments created by a linking script without a PHDRS
// clause may be affected by section sizes and alignments. There is
// layout. In order to be able to restart the section layout, we keep
// a copy of the segment list right before the relaxation loop and use
// that to restore the segments.
-//
-// PASS is the current relaxation pass number.
+//
+// PASS is the current relaxation pass number.
// SYMTAB is a symbol table.
// PLOAD_SEG is the address of a pointer for the load segment.
// PHDR_SEG is a pointer to the PHDR segment.
else if (parameters->options().relocatable())
load_seg = NULL;
else
- load_seg = this->find_first_load_seg();
+ load_seg = this->find_first_load_seg(target);
if (parameters->options().oformat_enum()
!= General_options::OBJECT_FORMAT_ELF)
load_seg->add_initial_output_data(z);
}
if (load_seg != NULL)
- load_seg->add_initial_output_data(segment_headers);
+ load_seg->add_initial_output_data(segment_headers);
if (phdr_seg != NULL)
- phdr_seg->add_initial_output_data(segment_headers);
+ phdr_seg->add_initial_output_data(segment_headers);
}
// Lay out the file header.
++it)
{
if (fnmatch((*it).c_str(), section_name.c_str(), FNM_NOESCAPE) == 0)
- {
- map_it = this->input_section_position_.find(*it);
- gold_assert(map_it != this->input_section_position_.end());
- return map_it->second;
- }
+ {
+ map_it = this->input_section_position_.find(*it);
+ gold_assert(map_it != this->input_section_position_.end());
+ return map_it->second;
+ }
}
return 0;
}
in.open(filename);
if (!in)
gold_fatal(_("unable to open --section-ordering-file file %s: %s"),
- filename, strerror(errno));
+ filename, strerror(errno));
std::getline(in, line); // this chops off the trailing \n, if any
unsigned int position = 1;
while (in)
{
if (!line.empty() && line[line.length() - 1] == '\r') // Windows
- line.resize(line.length() - 1);
+ line.resize(line.length() - 1);
// Ignore comments, beginning with '#'
if (line[0] == '#')
- {
- std::getline(in, line);
- continue;
- }
+ {
+ std::getline(in, line);
+ continue;
+ }
this->input_section_position_[line] = position;
// Store all glob patterns in a vector.
if (is_wildcard_string(line.c_str()))
- this->input_section_glob_.push_back(line);
+ this->input_section_glob_.push_back(line);
position++;
std::getline(in, line);
}
std::vector<Symbol*> dynamic_symbols;
unsigned int local_dynamic_count;
Versions versions(*this->script_options()->version_script_info(),
- &this->dynpool_);
+ &this->dynpool_);
this->create_dynamic_symtab(input_objects, symtab, &dynstr,
&local_dynamic_count, &dynamic_symbols,
&versions);
if ((!parameters->options().shared()
|| parameters->options().dynamic_linker() != NULL)
&& this->interp_segment_ == NULL)
- this->create_interp(target);
+ this->create_interp(target);
// Finish the .dynamic section to hold the dynamic data, and put
// it in a PT_DYNAMIC segment.
// after we call create_version_sections.
this->set_dynamic_symbol_size(symtab);
}
-
+
// Create segment headers.
Output_segment_headers* segment_headers =
(parameters->options().relocatable()
// a linker script.
if (this->script_options_->saw_sections_clause())
this->place_orphan_sections_in_script();
-
+
Output_segment* load_seg;
off_t off;
unsigned int shndx;
// Take a snapshot of the section layout as needed.
if (target->may_relax())
this->prepare_for_relaxation();
-
+
// Run the relaxation loop to lay out sections.
do
{
const char* incremental_strtab_name =
this->namepool_.add(".gnu_incremental_strtab", false, NULL);
Output_section* incremental_strtab_os = this->make_output_section(incremental_strtab_name,
- elfcpp::SHT_STRTAB, 0,
- ORDER_INVALID, false);
+ elfcpp::SHT_STRTAB, 0,
+ ORDER_INVALID, false);
Output_data_strtab* strtab_data =
new Output_data_strtab(incr->get_stringpool());
incremental_strtab_os->add_output_section_data(strtab_data);
// Find the PT_LOAD segments, and set their addresses and offsets
// and their section's addresses and offsets.
- uint64_t addr;
+ uint64_t start_addr;
if (parameters->options().user_set_Ttext())
- addr = parameters->options().Ttext();
+ start_addr = parameters->options().Ttext();
else if (parameters->options().output_is_position_independent())
- addr = 0;
+ start_addr = 0;
else
- addr = target->default_text_segment_address();
+ start_addr = target->default_text_segment_address();
+
+ uint64_t addr = start_addr;
off_t off = 0;
// If LOAD_SEG is NULL, then the file header and segment headers
const bool check_sections = parameters->options().check_sections();
Output_segment* last_load_segment = NULL;
+ unsigned int shndx_begin = *pshndx;
+ unsigned int shndx_load_seg = *pshndx;
+
for (Segment_list::iterator p = this->segment_list_.begin();
p != this->segment_list_.end();
++p)
{
if ((*p)->type() == elfcpp::PT_LOAD)
{
- if (load_seg != NULL && load_seg != *p)
- gold_unreachable();
- load_seg = NULL;
+ if (target->isolate_execinstr())
+ {
+ // When we hit the segment that should contain the
+ // file headers, reset the file offset so we place
+ // it and subsequent segments appropriately.
+ // We'll fix up the preceding segments below.
+ if (load_seg == *p)
+ {
+ if (off == 0)
+ load_seg = NULL;
+ else
+ {
+ off = 0;
+ shndx_load_seg = *pshndx;
+ }
+ }
+ }
+ else
+ {
+ // Verify that the file headers fall into the first segment.
+ if (load_seg != NULL && load_seg != *p)
+ gold_unreachable();
+ load_seg = NULL;
+ }
bool are_addresses_set = (*p)->are_addresses_set();
if (are_addresses_set)
addr = align_address(addr, (*p)->maximum_alignment());
aligned_addr = addr;
- if ((addr & (abi_pagesize - 1)) != 0)
- addr = addr + abi_pagesize;
+ if (load_seg == *p)
+ {
+ // This is the segment that will contain the file
+ // headers, so its offset will have to be exactly zero.
+ gold_assert(orig_off == 0);
+
+ // If the target wants a fixed minimum distance from the
+ // text segment to the read-only segment, move up now.
+ uint64_t min_addr = start_addr + target->rosegment_gap();
+ if (addr < min_addr)
+ addr = min_addr;
+
+ // But this is not the first segment! To make its
+ // address congruent with its offset, that address better
+ // be aligned to the ABI-mandated page size.
+ addr = align_address(addr, abi_pagesize);
+ aligned_addr = addr;
+ }
+ else
+ {
+ if ((addr & (abi_pagesize - 1)) != 0)
+ addr = addr + abi_pagesize;
- off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1));
+ off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1));
+ }
}
if (!parameters->options().nmagic()
&& !parameters->options().omagic())
off = align_file_offset(off, addr, abi_pagesize);
- else if (load_seg == NULL)
+ else
{
// This is -N or -n with a section script which prevents
// us from using a load segment. We need to ensure that
uint64_t new_addr = (*p)->set_section_addresses(this, false, addr,
&increase_relro,
&has_relro,
- &off, pshndx);
+ &off, pshndx);
// Now that we know the size of this segment, we may be able
// to save a page in memory, at the cost of wasting some
new_addr = (*p)->set_section_addresses(this, true, addr,
&increase_relro,
&has_relro,
- &off, pshndx);
+ &off, pshndx);
}
}
}
}
+ if (load_seg != NULL && target->isolate_execinstr())
+ {
+ // Process the early segments again, setting their file offsets
+ // so they land after the segments starting at LOAD_SEG.
+ off = align_file_offset(off, 0, target->abi_pagesize());
+
+ for (Segment_list::iterator p = this->segment_list_.begin();
+ *p != load_seg;
+ ++p)
+ {
+ if ((*p)->type() == elfcpp::PT_LOAD)
+ {
+ // We repeat the whole job of assigning addresses and
+ // offsets, but we really only want to change the offsets and
+ // must ensure that the addresses all come out the same as
+ // they did the first time through.
+ bool has_relro = false;
+ const uint64_t old_addr = (*p)->vaddr();
+ const uint64_t old_end = old_addr + (*p)->memsz();
+ uint64_t new_addr = (*p)->set_section_addresses(this, true,
+ old_addr,
+ &increase_relro,
+ &has_relro,
+ &off,
+ &shndx_begin);
+ gold_assert(new_addr == old_end);
+ }
+ }
+
+ gold_assert(shndx_begin == shndx_load_seg);
+ }
+
// Handle the non-PT_LOAD segments, setting their offsets from their
// section's offsets.
for (Segment_list::iterator p = this->segment_list_.begin();
}
if (pass == BEFORE_INPUT_SECTIONS_PASS
- && (*p)->after_input_sections())
- continue;
+ && (*p)->after_input_sections())
+ continue;
else if (pass == POSTPROCESSING_SECTIONS_PASS
- && (!(*p)->after_input_sections()
- || (*p)->type() == elfcpp::SHT_STRTAB))
- continue;
+ && (!(*p)->after_input_sections()
+ || (*p)->type() == elfcpp::SHT_STRTAB))
+ continue;
else if (pass == STRTAB_AFTER_POSTPROCESSING_SECTIONS_PASS
- && (!(*p)->after_input_sections()
- || (*p)->type() != elfcpp::SHT_STRTAB))
- continue;
+ && (!(*p)->after_input_sections()
+ || (*p)->type() != elfcpp::SHT_STRTAB))
+ continue;
if (!parameters->incremental_update())
{
if (off == -1)
{
if (is_debugging_enabled(DEBUG_INCREMENTAL))
- this->free_list_.dump();
+ this->free_list_.dump();
gold_assert((*p)->output_section() != NULL);
gold_fallback(_("out of patch space for section %s; "
"relink with --incremental-full"),
off += (*p)->data_size();
if (off > maxoff)
- maxoff = off;
+ maxoff = off;
// At this point the name must be set.
if (pass != STRTAB_AFTER_POSTPROCESSING_SECTIONS_PASS)
++p)
{
unsigned int index = (*p)->finalize_local_symbols(local_symbol_index,
- off, symtab);
+ off, symtab);
off += (index - local_symbol_index) * symsize;
local_symbol_index = index;
}
else
{
symtab_off = this->allocate(off, align, *poff);
- if (off == -1)
+ if (off == -1)
gold_fallback(_("out of patch space for symbol table; "
"relink with --incremental-full"));
gold_debug(DEBUG_INCREMENTAL,
void
Layout::create_dynamic_symtab(const Input_objects* input_objects,
- Symbol_table* symtab,
+ Symbol_table* symtab,
Output_section** pdynstr,
unsigned int* plocal_dynamic_count,
std::vector<Symbol*>* pdynamic_symbols,
{
case elfcpp::SHT_FINI_ARRAY:
odyn->add_section_address(elfcpp::DT_FINI_ARRAY, *p);
- odyn->add_section_size(elfcpp::DT_FINI_ARRAYSZ, *p);
+ odyn->add_section_size(elfcpp::DT_FINI_ARRAYSZ, *p);
break;
case elfcpp::SHT_INIT_ARRAY:
odyn->add_section_address(elfcpp::DT_INIT_ARRAY, *p);
- odyn->add_section_size(elfcpp::DT_INIT_ARRAYSZ, *p);
+ odyn->add_section_size(elfcpp::DT_INIT_ARRAYSZ, *p);
break;
case elfcpp::SHT_PREINIT_ARRAY:
odyn->add_section_address(elfcpp::DT_PREINIT_ARRAY, *p);
- odyn->add_section_size(elfcpp::DT_PREINIT_ARRAYSZ, *p);
+ odyn->add_section_size(elfcpp::DT_PREINIT_ARRAYSZ, *p);
break;
default:
break;
}
-
+
// Add a DT_RPATH entry if needed.
const General_options::Dir_list& rpath(parameters->options().rpath());
if (!rpath.empty())
{
std::string rpath_val;
for (General_options::Dir_list::const_iterator p = rpath.begin();
- p != rpath.end();
- ++p)
- {
- if (rpath_val.empty())
- rpath_val = p->name();
- else
- {
- // Eliminate duplicates.
- General_options::Dir_list::const_iterator q;
- for (q = rpath.begin(); q != p; ++q)
+ p != rpath.end();
+ ++p)
+ {
+ if (rpath_val.empty())
+ rpath_val = p->name();
+ else
+ {
+ // Eliminate duplicates.
+ General_options::Dir_list::const_iterator q;
+ for (q = rpath.begin(); q != p; ++q)
if (q->name() == p->name())
- break;
- if (q == p)
- {
- rpath_val += ':';
- rpath_val += p->name();
- }
- }
- }
+ break;
+ if (q == p)
+ {
+ rpath_val += ':';
+ rpath_val += p->name();
+ }
+ }
+ }
odyn->add_string(elfcpp::DT_RPATH, rpath_val);
if (parameters->options().enable_new_dtags())
if (!this->script_options_->saw_sections_clause())
{
for (Segment_list::const_iterator p = this->segment_list_.begin();
- p != this->segment_list_.end();
- ++p)
- {
- if ((*p)->type() == elfcpp::PT_LOAD
+ p != this->segment_list_.end();
+ ++p)
+ {
+ if ((*p)->type() == elfcpp::PT_LOAD
&& ((*p)->flags() & elfcpp::PF_W) == 0
- && (*p)->has_dynamic_reloc())
- {
- have_textrel = true;
- break;
- }
- }
+ && (*p)->has_dynamic_reloc())
+ {
+ have_textrel = true;
+ break;
+ }
+ }
}
else
{
// relocations. If those sections wind up in writable segments,
// then we have created an unnecessary DT_TEXTREL entry.
for (Section_list::const_iterator p = this->section_list_.begin();
- p != this->section_list_.end();
- ++p)
- {
- if (((*p)->flags() & elfcpp::SHF_ALLOC) != 0
- && ((*p)->flags() & elfcpp::SHF_WRITE) == 0
- && (*p)->has_dynamic_reloc())
- {
- have_textrel = true;
- break;
- }
- }
+ p != this->section_list_.end();
+ ++p)
+ {
+ if (((*p)->flags() & elfcpp::SHF_ALLOC) != 0
+ && ((*p)->flags() & elfcpp::SHF_WRITE) == 0
+ && (*p)->has_dynamic_reloc())
+ {
+ have_textrel = true;
+ break;
+ }
+ }
}
if (parameters->options().filter() != NULL)
unsigned int shndx,
bool is_comdat,
bool is_group_name,
- Kept_section** kept_section)
+ Kept_section** kept_section)
{
// It's normal to see a couple of entries here, for the x86 thunk
// sections. If we see more than a few, we're linking a C++
// If the kept group is from a plugin object, and we're in the
// replacement phase, accept the new one as a replacement.
if (ins.first->second.object() == NULL
- && parameters->options().plugins()->in_replacement_phase())
- {
+ && parameters->options().plugins()->in_replacement_phase())
+ {
ins.first->second.set_object(object);
ins.first->second.set_shndx(shndx);
- return true;
- }
+ return true;
+ }
return false;
}
else if (is_group_name)
// layout.h -- lay out output file sections for gold -*- C++ -*-
-// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012
+// Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
Layout_task_runner(const General_options& options,
const Input_objects* input_objects,
Symbol_table* symtab,
- Target* target,
+ Target* target,
Layout* layout,
Mapfile* mapfile)
: options_(options), input_objects_(input_objects), symtab_(symtab),
std::map<Section_id, unsigned int>*
get_section_order_map()
{ return &this->section_order_map_; }
-
+
bool
is_section_ordering_specified()
{ return this->section_ordering_specified_; }
{
// Debugging sections can only be recognized by name.
return (strncmp(name, ".debug", sizeof(".debug") - 1) == 0
- || strncmp(name, ".zdebug", sizeof(".zdebug") - 1) == 0
- || strncmp(name, ".gnu.linkonce.wi.",
- sizeof(".gnu.linkonce.wi.") - 1) == 0
- || strncmp(name, ".line", sizeof(".line") - 1) == 0
- || strncmp(name, ".stab", sizeof(".stab") - 1) == 0);
+ || strncmp(name, ".zdebug", sizeof(".zdebug") - 1) == 0
+ || strncmp(name, ".gnu.linkonce.wi.",
+ sizeof(".gnu.linkonce.wi.") - 1) == 0
+ || strncmp(name, ".line", sizeof(".line") - 1) == 0
+ || strncmp(name, ".stab", sizeof(".stab") - 1) == 0);
}
// Return true if RELOBJ is an input file whose base name matches
// *KEPT_SECTION is set to the internal copy and the function return
// false.
bool
- find_or_add_kept_section(const std::string& name, Relobj* object,
+ find_or_add_kept_section(const std::string& name, Relobj* object,
unsigned int shndx, bool is_comdat,
bool is_group_name, Kept_section** kept_section);
// Attach sections to segments.
void
- attach_sections_to_segments();
+ attach_sections_to_segments(const Target*);
// For relaxation clean up, we need to know output section data created
// from a linker script.
// Find the first read-only PT_LOAD segment, creating one if
// necessary.
Output_segment*
- find_first_load_seg();
+ find_first_load_seg(const Target*);
// Count the local symbols in the regular symbol table and the dynamic
// symbol table, and build the respective string pools.
// Attach a section to a segment.
void
- attach_section_to_segment(Output_section*);
+ attach_section_to_segment(const Target*, Output_section*);
// Get section order.
Output_section_order
// Attach an allocated section to a segment.
void
- attach_allocated_section_to_segment(Output_section*);
+ attach_allocated_section_to_segment(const Target*, Output_section*);
// Make the .eh_frame section.
Output_section*
bool
segment_precedes(const Output_segment* seg1, const Output_segment* seg2);
- // Use to save and restore segments during relaxation.
+ // Use to save and restore segments during relaxation.
typedef Unordered_map<const Output_segment*, const Output_segment*>
Segment_states;
Relaxation_debug_check()
: section_infos_()
{ }
-
+
// Check that sections and special data are in reset states.
void
check_output_data_for_reset_values(const Layout::Section_list&,
const Layout::Data_list&);
-
+
// Record information of a section list.
void
read_sections(const Layout::Section_list&);
// Verify a section list with recorded information.
void
verify_sections(const Layout::Section_list&);
-
+
private:
// Information we care about a section.
struct Section_info
--- /dev/null
+// nacl.cc -- Native Client support for gold
+
+// Copyright 2012 Free Software Foundation, Inc.
+
+// This file is part of gold.
+
+// 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 3 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., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+#include "gold.h"
+
+#include <cstdio>
+
+#include "nacl.h"
+#include "elfcpp.h"
+
+namespace gold
+{
+
+// Copied from object.cc:Object::error.
+void
+Sniff_file::error(const char* format, ...) const
+{
+ va_list args;
+ va_start(args, format);
+ char* buf = NULL;
+ if (vasprintf(&buf, format, args) < 0)
+ gold_nomem();
+ va_end(args);
+ gold_error(_("%s: %s"), this->file_.filename().c_str(), buf);
+ free(buf);
+}
+
+} // end namespace gold
--- /dev/null
+// nacl.h -- Native Client support for gold -*- C++ -*-
+
+// Copyright 2012 Free Software Foundation, Inc.
+
+// This file is part of gold.
+
+// 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 3 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., 51 Franklin Street - Fifth Floor, Boston,
+// MA 02110-1301, USA.
+
+#include "elfcpp_file.h"
+#include "fileread.h"
+#include "layout.h"
+#include "target-select.h"
+#include "target.h"
+
+#ifndef GOLD_NACL_H
+#define GOLD_NACL_H
+
+namespace gold
+{
+
+class Sniff_file
+{
+ public:
+ Sniff_file(Input_file* input_file, off_t offset)
+ : file_(input_file->file()), offset_(offset)
+ { }
+
+ class Location
+ {
+ public:
+ Location(off_t file_offset, off_t data_size)
+ : offset_(file_offset), size_(data_size)
+ { }
+
+ inline off_t offset() const
+ { return this->offset_; }
+
+ inline section_size_type size() const
+ { return this->size_; }
+
+ private:
+ off_t offset_;
+ section_size_type size_;
+ };
+
+ class View
+ {
+ public:
+ View(File_read& file, off_t file_offset, off_t data_size)
+ : data_(file.get_view(0, file_offset, data_size, false, false))
+ { }
+
+ const unsigned char* data()
+ { return this->data_; }
+
+ private:
+ const unsigned char* data_;
+ };
+
+ View view(off_t file_offset, off_t data_size)
+ {
+ return View(this->file_, this->offset_ + file_offset, data_size);
+ }
+
+ View view(Location loc)
+ {
+ return this->view(loc.offset(), loc.size());
+ }
+
+ // Report an error.
+ void
+ error(const char* format, ...) const ATTRIBUTE_PRINTF_2;
+
+ private:
+ File_read& file_;
+ off_t offset_;
+};
+
+
+template<class base_selector, class nacl_target>
+class Target_selector_nacl : public base_selector
+{
+ public:
+ Target_selector_nacl(const char* nacl_abi_name,
+ const char* bfd_name, const char* emulation)
+ : base_selector(), is_nacl_(false), nacl_abi_name_(nacl_abi_name),
+ bfd_name_(bfd_name), emulation_(emulation)
+ { }
+
+ protected:
+ virtual Target*
+ do_instantiate_target()
+ {
+ if (this->is_nacl_)
+ return new nacl_target();
+ return this->base_selector::do_instantiate_target();
+ }
+
+ virtual Target*
+ do_recognize(Input_file* file, off_t offset,
+ int machine, int osabi, int abiversion)
+ {
+ this->is_nacl_ = file != NULL && this->recognize_nacl_file(file, offset);
+ if (this->is_nacl_)
+ return this->instantiate_target();
+ return this->base_selector::do_recognize(file, offset,
+ machine, osabi, abiversion);
+ }
+
+ virtual Target*
+ do_recognize_by_bfd_name(const char* name)
+ {
+ gold_assert(this->bfd_name_ != NULL);
+ this->is_nacl_ = strcmp(name, this->bfd_name_) == 0;
+ if (this->is_nacl_)
+ return this->instantiate_target();
+ return this->base_selector::do_recognize_by_bfd_name(name);
+ }
+
+ virtual void
+ do_supported_bfd_names(std::vector<const char*>* names)
+ {
+ gold_assert(this->bfd_name_ != NULL);
+ this->base_selector::do_supported_bfd_names(names);
+ names->push_back(this->bfd_name_);
+ }
+
+ virtual void
+ do_supported_emulations(std::vector<const char*>* emulations)
+ {
+ gold_assert(this->emulation_ != NULL);
+ this->base_selector::do_supported_emulations(emulations);
+ emulations->push_back(this->emulation_);
+ }
+
+ virtual const char*
+ do_target_bfd_name(const Target* target)
+ {
+ return (!this->is_our_target(target)
+ ? NULL
+ : (this->is_nacl_
+ ? this->bfd_name_
+ : base_selector::do_target_bfd_name(target)));
+ }
+
+ private:
+ bool
+ recognize_nacl_file(Input_file* input_file, off_t offset)
+ {
+ if (this->is_big_endian())
+ {
+#if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG)
+# ifdef HAVE_TARGET_32_BIG
+ if (this->get_size() == 32)
+ return do_recognize_nacl_file<32, true>(input_file, offset);
+# endif
+# ifdef HAVE_TARGET_64_BIG
+ if (this->get_size() == 64)
+ return do_recognize_nacl_file<64, true>(input_file, offset);
+# endif
+#endif
+ gold_unreachable();
+ }
+ else
+ {
+#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE)
+# ifdef HAVE_TARGET_32_LITTLE
+ if (this->get_size() == 32)
+ return do_recognize_nacl_file<32, false>(input_file, offset);
+# endif
+# ifdef HAVE_TARGET_64_LITTLE
+ if (this->get_size() == 64)
+ return do_recognize_nacl_file<64, false>(input_file, offset);
+# endif
+#endif
+ gold_unreachable();
+ }
+ }
+
+ template<int size, bool big_endian>
+ bool
+ do_recognize_nacl_file(Input_file* input_file, off_t offset)
+ {
+ Sniff_file file(input_file, offset);
+ elfcpp::Elf_file<size, big_endian, Sniff_file> elf_file(&file);
+ const unsigned int shnum = elf_file.shnum();
+ for (unsigned int shndx = 1; shndx < shnum; ++shndx)
+ {
+ if (elf_file.section_type(shndx) == elfcpp::SHT_NOTE)
+ {
+ Sniff_file::Location loc = elf_file.section_contents(shndx);
+ if (loc.size() < (3 * 4
+ + align_address(sizeof "NaCl", 4)
+ + align_address(nacl_abi_name_.size() + 1, 4)))
+ continue;
+ Sniff_file::View view(file.view(loc));
+ const unsigned char* note_data = view.data();
+ if ((elfcpp::Swap<32, big_endian>::readval(note_data + 0)
+ == sizeof "NaCl")
+ && (elfcpp::Swap<32, big_endian>::readval(note_data + 4)
+ == nacl_abi_name_.size() + 1)
+ && (elfcpp::Swap<32, big_endian>::readval(note_data + 8)
+ == elfcpp::NT_VERSION))
+ {
+ const unsigned char* name = note_data + 12;
+ const unsigned char* desc = (name
+ + align_address(sizeof "NaCl", 4));
+ if (memcmp(name, "NaCl", sizeof "NaCl") == 0
+ && memcmp(desc, nacl_abi_name_.c_str(),
+ nacl_abi_name_.size() + 1) == 0)
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ // Whether we decided this was the NaCl target variant.
+ bool is_nacl_;
+ // The string found in the NaCl ABI note.
+ std::string nacl_abi_name_;
+ // BFD name of NaCl target, for compatibility.
+ const char* const bfd_name_;
+ // GNU linker emulation for this NaCl target, for compatibility.
+ const char* const emulation_;
+};
+
+} // end namespace gold
+
+#endif // !defined(GOLD_NACL_H)
// object.cc -- support for an object file for linking in gold
-// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012
+// Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
// Class Relobj
// To copy the symbols data read from the file to a local data structure.
-// This function is called from do_layout only while doing garbage
+// This function is called from do_layout only while doing garbage
// collection.
void
-Relobj::copy_symbols_data(Symbols_data* gc_sd, Read_symbols_data* sd,
- unsigned int section_header_size)
+Relobj::copy_symbols_data(Symbols_data* gc_sd, Read_symbols_data* sd,
+ unsigned int section_header_size)
{
- gc_sd->section_headers_data =
- new unsigned char[(section_header_size)];
+ gc_sd->section_headers_data =
+ new unsigned char[(section_header_size)];
memcpy(gc_sd->section_headers_data, sd->section_headers->data(),
- section_header_size);
- gc_sd->section_names_data =
- new unsigned char[sd->section_names_size];
+ section_header_size);
+ gc_sd->section_names_data =
+ new unsigned char[sd->section_names_size];
memcpy(gc_sd->section_names_data, sd->section_names->data(),
- sd->section_names_size);
+ sd->section_names_size);
gc_sd->section_names_size = sd->section_names_size;
if (sd->symbols != NULL)
{
- gc_sd->symbols_data =
- new unsigned char[sd->symbols_size];
+ gc_sd->symbols_data =
+ new unsigned char[sd->symbols_size];
memcpy(gc_sd->symbols_data, sd->symbols->data(),
- sd->symbols_size);
+ sd->symbols_size);
}
else
{
if (sd->symbol_names != NULL)
{
gc_sd->symbol_names_data =
- new unsigned char[sd->symbol_names_size];
+ new unsigned char[sd->symbol_names_size];
memcpy(gc_sd->symbol_names_data, sd->symbol_names->data(),
- sd->symbol_names_size);
+ sd->symbol_names_size);
}
else
{
bool
Relobj::is_section_name_included(const char* name)
{
- if (is_prefix_of(".ctors", name)
- || is_prefix_of(".dtors", name)
- || is_prefix_of(".note", name)
- || is_prefix_of(".init", name)
- || is_prefix_of(".fini", name)
- || is_prefix_of(".gcc_except_table", name)
- || is_prefix_of(".jcr", name)
- || is_prefix_of(".preinit_array", name)
- || (is_prefix_of(".text", name)
- && strstr(name, "personality"))
- || (is_prefix_of(".data", name)
- && strstr(name, "personality"))
+ if (is_prefix_of(".ctors", name)
+ || is_prefix_of(".dtors", name)
+ || is_prefix_of(".note", name)
+ || is_prefix_of(".init", name)
+ || is_prefix_of(".fini", name)
+ || is_prefix_of(".gcc_except_table", name)
+ || is_prefix_of(".jcr", name)
+ || is_prefix_of(".preinit_array", name)
+ || (is_prefix_of(".text", name)
+ && strstr(name, "personality"))
+ || (is_prefix_of(".data", name)
+ && strstr(name, "personality"))
|| (is_prefix_of(".gnu.linkonce.d", name)
&& strstr(name, "personality")))
{
- return true;
+ return true;
}
return false;
}
if (memmem(names, sd->section_names_size, ".eh_frame", 10) != NULL)
{
if (this->find_eh_frame(pshdrs, names, sd->section_names_size))
- this->has_eh_frame_ = true;
+ this->has_eh_frame_ = true;
}
if (memmem(names, sd->section_names_size, ".zdebug_", 8) != NULL)
this->compressed_sections_ =
- build_compressed_section_map(pshdrs, this->shnum(), names,
+ build_compressed_section_map(pshdrs, this->shnum(), names,
sd->section_names_size, this);
if (this->has_eh_frame_
}
typename This::Shdr member_shdr(shdrs + sym_shndx * This::shdr_size);
if (member_shdr.get_sh_name() < section_names_size)
- signature = section_names + member_shdr.get_sh_name();
+ signature = section_names + member_shdr.get_sh_name();
}
// Record this section group in the layout, and see whether we've already
// Check for an earlier section number, since we're going to get
// it wrong--we may have already decided to include the section.
if (shndx < index)
- this->error(_("invalid section group %u refers to earlier section %u"),
- index, shndx);
+ this->error(_("invalid section group %u refers to earlier section %u"),
+ index, shndx);
// Get the name of the member section.
typename This::Shdr member_shdr(shdrs + shndx * This::shdr_size);
if (member_shdr.get_sh_name() >= section_names_size)
- {
- // This is an error, but it will be diagnosed eventually
- // in do_layout, so we don't need to do anything here but
- // ignore it.
- continue;
- }
+ {
+ // This is an error, but it will be diagnosed eventually
+ // in do_layout, so we don't need to do anything here but
+ // ignore it.
+ continue;
+ }
std::string mname(section_names + member_shdr.get_sh_name());
if (include_group)
member_shdr.get_sh_size());
}
else
- {
- (*omit)[shndx] = true;
+ {
+ (*omit)[shndx] = true;
if (is_comdat)
- {
+ {
Relobj* kept_object = kept_section->object();
if (kept_section->is_comdat())
{
this->set_kept_comdat_section(shndx, kept_object,
kept_section->shndx());
}
- }
- }
+ }
+ }
}
if (relocate_group)
// Lay out the input sections. We walk through the sections and check
// whether they should be included in the link. If they should, we
// pass them to the Layout object, which will return an output section
-// and an offset.
-// During garbage collection (--gc-sections) and identical code folding
-// (--icf), this function is called twice. When it is called the first
+// and an offset.
+// During garbage collection (--gc-sections) and identical code folding
+// (--icf), this function is called twice. When it is called the first
// time, it is for setting up some sections as roots to a work-list for
-// --gc-sections and to do comdat processing. Actual layout happens the
-// second time around after all the relevant sections have been determined.
-// The first time, is_worklist_ready or is_icf_ready is false. It is then
-// set to true after the garbage collection worklist or identical code
-// folding is processed and the relevant sections to be kept are
+// --gc-sections and to do comdat processing. Actual layout happens the
+// second time around after all the relevant sections have been determined.
+// The first time, is_worklist_ready or is_icf_ready is false. It is then
+// set to true after the garbage collection worklist or identical code
+// folding is processed and the relevant sections to be kept are
// determined. Then, this function is called again to layout the sections.
template<int size, bool big_endian>
Read_symbols_data* sd)
{
const unsigned int shnum = this->shnum();
- bool is_gc_pass_one = ((parameters->options().gc_sections()
- && !symtab->gc()->is_worklist_ready())
- || (parameters->options().icf_enabled()
- && !symtab->icf()->is_icf_ready()));
-
- bool is_gc_pass_two = ((parameters->options().gc_sections()
- && symtab->gc()->is_worklist_ready())
- || (parameters->options().icf_enabled()
- && symtab->icf()->is_icf_ready()));
+ bool is_gc_pass_one = ((parameters->options().gc_sections()
+ && !symtab->gc()->is_worklist_ready())
+ || (parameters->options().icf_enabled()
+ && !symtab->icf()->is_icf_ready()));
+
+ bool is_gc_pass_two = ((parameters->options().gc_sections()
+ && symtab->gc()->is_worklist_ready())
+ || (parameters->options().icf_enabled()
+ && symtab->icf()->is_icf_ready()));
bool is_gc_or_icf = (parameters->options().gc_sections()
- || parameters->options().icf_enabled());
+ || parameters->options().icf_enabled());
// Both is_gc_pass_one and is_gc_pass_two should not be true.
gold_assert(!(is_gc_pass_one && is_gc_pass_two));
Symbols_data* gc_sd = NULL;
if (is_gc_pass_one)
{
- // During garbage collection save the symbols data to use it when
- // re-entering this function.
+ // During garbage collection save the symbols data to use it when
+ // re-entering this function.
gc_sd = new Symbols_data;
this->copy_symbols_data(gc_sd, sd, This::shdr_size * shnum);
this->set_symbols_data(gc_sd);
section_size_type symbols_size;
const unsigned char* symbol_names_data = NULL;
section_size_type symbol_names_size;
-
+
if (is_gc_or_icf)
{
section_headers_data = gc_sd->section_headers_data;
section_headers_data = sd->section_headers->data();
section_names_size = sd->section_names_size;
if (sd->symbols != NULL)
- symbols_data = sd->symbols->data();
+ symbols_data = sd->symbols->data();
symbols_size = sd->symbols_size;
if (sd->symbol_names != NULL)
- symbol_names_data = sd->symbol_names->data();
+ symbol_names_data = sd->symbol_names->data();
symbol_names_size = sd->symbol_names_size;
}
const unsigned char* pshdrs;
// Get the section names.
- const unsigned char* pnamesu = (is_gc_or_icf)
- ? gc_sd->section_names_data
- : sd->section_names->data();
+ const unsigned char* pnamesu = (is_gc_or_icf)
+ ? gc_sd->section_names_data
+ : sd->section_names->data();
const char* pnames = reinterpret_cast<const char*>(pnamesu);
// Count the number of sections whose layout will be deferred.
if (should_defer_layout && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC))
- ++num_sections_to_defer;
+ ++num_sections_to_defer;
unsigned int sh_type = shdr.get_sh_type();
if (sh_type == elfcpp::SHT_REL || sh_type == elfcpp::SHT_RELA)
if (this->input_file()->just_symbols())
{
if (!is_gc_pass_two)
- {
- delete sd->section_headers;
- sd->section_headers = NULL;
- delete sd->section_names;
- sd->section_names = NULL;
- }
+ {
+ delete sd->section_headers;
+ sd->section_headers = NULL;
+ delete sd->section_names;
+ sd->section_names = NULL;
+ }
return;
}
const char* name = pnames + shdr.get_sh_name();
if (!is_gc_pass_two)
- {
- if (this->handle_gnu_warning_section(name, i, symtab))
- {
- if (!relocatable && !parameters->options().shared())
- omit[i] = true;
+ {
+ if (this->handle_gnu_warning_section(name, i, symtab))
+ {
+ if (!relocatable && !parameters->options().shared())
+ omit[i] = true;
}
- // The .note.GNU-stack section is special. It gives the
- // protection flags that this object file requires for the stack
- // in memory.
- if (strcmp(name, ".note.GNU-stack") == 0)
- {
+ // The .note.GNU-stack section is special. It gives the
+ // protection flags that this object file requires for the stack
+ // in memory.
+ if (strcmp(name, ".note.GNU-stack") == 0)
+ {
seen_gnu_stack = true;
gnu_stack_flags |= shdr.get_sh_flags();
omit[i] = true;
- }
+ }
// The .note.GNU-split-stack section is also special. It
// indicates that the object was compiled with
omit[i] = true;
}
- bool discard = omit[i];
- if (!discard)
- {
+ bool discard = omit[i];
+ if (!discard)
+ {
if (shdr.get_sh_type() == elfcpp::SHT_GROUP)
- {
- if (!this->include_section_group(symtab, layout, i, name,
- shdrs, pnames,
- section_names_size,
- &omit))
+ {
+ if (!this->include_section_group(symtab, layout, i, name,
+ shdrs, pnames,
+ section_names_size,
+ &omit))
+ discard = true;
+ }
+ else if ((shdr.get_sh_flags() & elfcpp::SHF_GROUP) == 0
+ && Layout::is_linkonce(name))
+ {
+ if (!this->include_linkonce_section(layout, i, name, shdr))
discard = true;
- }
- else if ((shdr.get_sh_flags() & elfcpp::SHF_GROUP) == 0
- && Layout::is_linkonce(name))
- {
- if (!this->include_linkonce_section(layout, i, name, shdr))
- discard = true;
- }
+ }
}
// Add the section to the incremental inputs layout.
incremental_inputs->report_input_section(this, i, name, sh_size);
}
- if (discard)
- {
+ if (discard)
+ {
// Do not include this section in the link.
out_sections[i] = NULL;
- out_section_offsets[i] = invalid_address;
+ out_section_offsets[i] = invalid_address;
continue;
- }
- }
-
+ }
+ }
+
if (is_gc_pass_one && parameters->options().gc_sections())
- {
- if (this->is_section_name_included(name)
- || shdr.get_sh_type() == elfcpp::SHT_INIT_ARRAY
- || shdr.get_sh_type() == elfcpp::SHT_FINI_ARRAY)
- {
- symtab->gc()->worklist().push(Section_id(this, i));
- }
- // If the section name XXX can be represented as a C identifier
- // it cannot be discarded if there are references to
- // __start_XXX and __stop_XXX symbols. These need to be
- // specially handled.
- if (is_cident(name))
- {
- symtab->gc()->add_cident_section(name, Section_id(this, i));
- }
- }
+ {
+ if (this->is_section_name_included(name)
+ || shdr.get_sh_type() == elfcpp::SHT_INIT_ARRAY
+ || shdr.get_sh_type() == elfcpp::SHT_FINI_ARRAY)
+ {
+ symtab->gc()->worklist().push(Section_id(this, i));
+ }
+ // If the section name XXX can be represented as a C identifier
+ // it cannot be discarded if there are references to
+ // __start_XXX and __stop_XXX symbols. These need to be
+ // specially handled.
+ if (is_cident(name))
+ {
+ symtab->gc()->add_cident_section(name, Section_id(this, i));
+ }
+ }
// When doing a relocatable link we are going to copy input
// reloc sections into the output. We only want to copy the
// determine which sections are being discarded, and discard the
// corresponding information.
if (!relocatable
- && strcmp(name, ".eh_frame") == 0
- && this->check_eh_frame_flags(&shdr))
- {
- if (is_gc_pass_one)
- {
- out_sections[i] = reinterpret_cast<Output_section*>(1);
- out_section_offsets[i] = invalid_address;
- }
- else if (should_defer_layout)
+ && strcmp(name, ".eh_frame") == 0
+ && this->check_eh_frame_flags(&shdr))
+ {
+ if (is_gc_pass_one)
+ {
+ out_sections[i] = reinterpret_cast<Output_section*>(1);
+ out_section_offsets[i] = invalid_address;
+ }
+ else if (should_defer_layout)
this->deferred_layout_.push_back(Deferred_layout(i, name,
pshdrs,
reloc_shndx[i],
reloc_type[i]));
else
- eh_frame_sections.push_back(i);
- continue;
- }
+ eh_frame_sections.push_back(i);
+ continue;
+ }
if (is_gc_pass_two && parameters->options().gc_sections())
- {
- // This is executed during the second pass of garbage
- // collection. do_layout has been called before and some
- // sections have been already discarded. Simply ignore
- // such sections this time around.
- if (out_sections[i] == NULL)
- {
- gold_assert(out_section_offsets[i] == invalid_address);
- continue;
- }
- if (((shdr.get_sh_flags() & elfcpp::SHF_ALLOC) != 0)
- && symtab->gc()->is_section_garbage(this, i))
- {
- if (parameters->options().print_gc_sections())
- gold_info(_("%s: removing unused section from '%s'"
- " in file '%s'"),
- program_name, this->section_name(i).c_str(),
- this->name().c_str());
- out_sections[i] = NULL;
- out_section_offsets[i] = invalid_address;
- continue;
- }
- }
+ {
+ // This is executed during the second pass of garbage
+ // collection. do_layout has been called before and some
+ // sections have been already discarded. Simply ignore
+ // such sections this time around.
+ if (out_sections[i] == NULL)
+ {
+ gold_assert(out_section_offsets[i] == invalid_address);
+ continue;
+ }
+ if (((shdr.get_sh_flags() & elfcpp::SHF_ALLOC) != 0)
+ && symtab->gc()->is_section_garbage(this, i))
+ {
+ if (parameters->options().print_gc_sections())
+ gold_info(_("%s: removing unused section from '%s'"
+ " in file '%s'"),
+ program_name, this->section_name(i).c_str(),
+ this->name().c_str());
+ out_sections[i] = NULL;
+ out_section_offsets[i] = invalid_address;
+ continue;
+ }
+ }
if (is_gc_pass_two && parameters->options().icf_enabled())
- {
- if (out_sections[i] == NULL)
- {
- gold_assert(out_section_offsets[i] == invalid_address);
- continue;
- }
- if (((shdr.get_sh_flags() & elfcpp::SHF_ALLOC) != 0)
- && symtab->icf()->is_section_folded(this, i))
- {
- if (parameters->options().print_icf_sections())
- {
- Section_id folded =
- symtab->icf()->get_folded_section(this, i);
- Relobj* folded_obj =
- reinterpret_cast<Relobj*>(folded.first);
- gold_info(_("%s: ICF folding section '%s' in file '%s'"
- "into '%s' in file '%s'"),
- program_name, this->section_name(i).c_str(),
- this->name().c_str(),
- folded_obj->section_name(folded.second).c_str(),
- folded_obj->name().c_str());
- }
- out_sections[i] = NULL;
- out_section_offsets[i] = invalid_address;
- continue;
- }
- }
+ {
+ if (out_sections[i] == NULL)
+ {
+ gold_assert(out_section_offsets[i] == invalid_address);
+ continue;
+ }
+ if (((shdr.get_sh_flags() & elfcpp::SHF_ALLOC) != 0)
+ && symtab->icf()->is_section_folded(this, i))
+ {
+ if (parameters->options().print_icf_sections())
+ {
+ Section_id folded =
+ symtab->icf()->get_folded_section(this, i);
+ Relobj* folded_obj =
+ reinterpret_cast<Relobj*>(folded.first);
+ gold_info(_("%s: ICF folding section '%s' in file '%s'"
+ "into '%s' in file '%s'"),
+ program_name, this->section_name(i).c_str(),
+ this->name().c_str(),
+ folded_obj->section_name(folded.second).c_str(),
+ folded_obj->name().c_str());
+ }
+ out_sections[i] = NULL;
+ out_section_offsets[i] = invalid_address;
+ continue;
+ }
+ }
// Defer layout here if input files are claimed by plugins. When gc
// is turned on this function is called twice. For the second call
// should_defer_layout should be false.
if (should_defer_layout && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC))
- {
- gold_assert(!is_gc_pass_two);
- this->deferred_layout_.push_back(Deferred_layout(i, name,
- pshdrs,
- reloc_shndx[i],
- reloc_type[i]));
- // Put dummy values here; real values will be supplied by
- // do_layout_deferred_sections.
- out_sections[i] = reinterpret_cast<Output_section*>(2);
- out_section_offsets[i] = invalid_address;
- continue;
- }
+ {
+ gold_assert(!is_gc_pass_two);
+ this->deferred_layout_.push_back(Deferred_layout(i, name,
+ pshdrs,
+ reloc_shndx[i],
+ reloc_type[i]));
+ // Put dummy values here; real values will be supplied by
+ // do_layout_deferred_sections.
+ out_sections[i] = reinterpret_cast<Output_section*>(2);
+ out_section_offsets[i] = invalid_address;
+ continue;
+ }
// During gc_pass_two if a section that was previously deferred is
// found, do not layout the section as layout_deferred_sections will
// do it later from gold.cc.
- if (is_gc_pass_two
- && (out_sections[i] == reinterpret_cast<Output_section*>(2)))
- continue;
+ if (is_gc_pass_two
+ && (out_sections[i] == reinterpret_cast<Output_section*>(2)))
+ continue;
if (is_gc_pass_one)
- {
- // This is during garbage collection. The out_sections are
- // assigned in the second call to this function.
- out_sections[i] = reinterpret_cast<Output_section*>(1);
- out_section_offsets[i] = invalid_address;
- }
+ {
+ // This is during garbage collection. The out_sections are
+ // assigned in the second call to this function.
+ out_sections[i] = reinterpret_cast<Output_section*>(1);
+ out_section_offsets[i] = invalid_address;
+ }
else
- {
- // When garbage collection is switched on the actual layout
- // only happens in the second call.
- this->layout_section(layout, i, name, shdr, reloc_shndx[i],
- reloc_type[i]);
+ {
+ // When garbage collection is switched on the actual layout
+ // only happens in the second call.
+ this->layout_section(layout, i, name, shdr, reloc_shndx[i],
+ reloc_type[i]);
// When generating a .gdb_index section, we do additional
// processing of .debug_info and .debug_types sections after all
|| strcmp(name, ".zdebug_types") == 0)
debug_types_sections.push_back(i);
}
- }
+ }
}
if (!is_gc_pass_two)
layout->layout_gnu_stack(seen_gnu_stack, gnu_stack_flags, this);
// When doing a relocatable link handle the reloc sections at the
- // end. Garbage collection and Identical Code Folding is not
- // turned on for relocatable code.
+ // end. Garbage collection and Identical Code Folding is not
+ // turned on for relocatable code.
if (emit_relocs)
this->size_relocatable_relocs();
Output_section* data_section = out_sections[data_shndx];
if (data_section == reinterpret_cast<Output_section*>(2))
- {
- // The layout for the data section was deferred, so we need
- // to defer the relocation section, too.
+ {
+ // The layout for the data section was deferred, so we need
+ // to defer the relocation section, too.
const char* name = pnames + shdr.get_sh_name();
- this->deferred_layout_relocs_.push_back(
- Deferred_layout(i, name, pshdr, 0, elfcpp::SHT_NULL));
+ this->deferred_layout_relocs_.push_back(
+ Deferred_layout(i, name, pshdr, 0, elfcpp::SHT_NULL));
out_sections[i] = reinterpret_cast<Output_section*>(2);
- out_section_offsets[i] = invalid_address;
- continue;
- }
+ out_section_offsets[i] = invalid_address;
+ continue;
+ }
if (data_section == NULL)
{
out_sections[i] = NULL;
- out_section_offsets[i] = invalid_address;
+ out_section_offsets[i] = invalid_address;
continue;
}
// If the section is not included, it is because the garbage collector
// decided it is not needed. Avoid reverting that decision.
if (!this->is_section_included(deferred->shndx_))
- continue;
+ continue;
if (parameters->options().relocatable()
|| deferred->name_ != ".eh_frame"
if (data_section == NULL)
{
out_sections[shndx] = NULL;
- out_section_offsets[shndx] = invalid_address;
+ out_section_offsets[shndx] = invalid_address;
continue;
}
sd->symbols->data() + sd->external_symbols_offset;
const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
size_t symcount = ((sd->symbols_size - sd->external_symbols_offset)
- / sym_size);
+ / sym_size);
const unsigned char* p = syms;
sd->symbols->data() + sd->external_symbols_offset;
const int sym_size = elfcpp::Elf_sizes<size>::sym_size;
size_t symcount = ((sd->symbols_size - sd->external_symbols_offset)
- / sym_size);
+ / sym_size);
const unsigned char* p = syms;
for (size_t i = 0; i < symcount; ++i, p += sym_size)
if ((shndx < shnum && out_sections[shndx] == NULL)
|| shndx == this->discarded_eh_frame_shndx_)
- {
+ {
lv.set_no_output_symtab_entry();
- gold_assert(!lv.needs_output_dynsym_entry());
- continue;
- }
+ gold_assert(!lv.needs_output_dynsym_entry());
+ continue;
+ }
if (sym.get_st_type() == elfcpp::STT_SECTION)
{
lv.set_no_output_symtab_entry();
- gold_assert(!lv.needs_output_dynsym_entry());
+ gold_assert(!lv.needs_output_dynsym_entry());
continue;
}
// If needed, add the symbol to the dynamic symbol table string pool.
if (lv.needs_output_dynsym_entry())
- {
- dynpool->add(name, true, NULL);
- ++dyncount;
- }
+ {
+ dynpool->add(name, true, NULL);
+ ++dyncount;
+ }
if (strip_all
|| (discard_all && lv.may_be_discarded_from_output_symtab()))
// Discard the local symbol if -retain_symbols_file is specified
// and the local symbol is not in that file.
if (!parameters->options().should_retain_symbol(name))
- {
- lv.set_no_output_symtab_entry();
- continue;
- }
+ {
+ lv.set_no_output_symtab_entry();
+ continue;
+ }
// Add the symbol to the symbol table string pool.
pool->add(name, true, NULL);
bool is_ordinary;
unsigned int shndx = lv_in->input_shndx(&is_ordinary);
-
+
// Set the output symbol value.
-
+
if (!is_ordinary)
{
if (shndx == elfcpp::SHN_ABS || Symbol::is_common_shndx(shndx))
lv_out->set_output_value(0);
return This::CFLV_ERROR;
}
-
+
Output_section* os = out_sections[shndx];
Address secoffset = out_offsets[shndx];
if (symtab->is_section_folded(this, shndx))
os = folded_obj->output_section(folded.second);
gold_assert(os != NULL);
secoffset = folded_obj->get_output_section_offset(folded.second);
-
+
// This could be a relaxed input section.
if (secoffset == invalid_address)
{
secoffset = relaxed_section->address() - os->address();
}
}
-
+
if (os == NULL)
{
// This local symbol belongs to a section we are discarding.
else if (secoffset == invalid_address)
{
uint64_t start;
-
+
// This is a SHF_MERGE section or one which otherwise
// requires special handling.
if (shndx == this->discarded_eh_frame_shndx_)
{
Symbol_value<size>& lv(this->local_values_[i]);
if (lv.needs_output_dynsym_entry())
- {
- lv.set_output_dynsym_index(index);
- ++index;
- }
+ {
+ lv.set_output_dynsym_index(index);
+ ++index;
+ }
}
return index;
}
if (sd != NULL)
{
const unsigned char* pshdrs = sd->section_headers_data
- + This::shdr_size * shndx;
+ + This::shdr_size * shndx;
typename This::Shdr shdr(pshdrs);
- return shdr.get_sh_flags();
+ return shdr.get_sh_flags();
}
// If sd is NULL, read the section header from the file.
- return this->elf_file_.section_flags(shndx);
+ return this->elf_file_.section_flags(shndx);
}
// Get the section's ent size from Symbols_data. Called by get_section_contents
gold_assert(sd != NULL);
const unsigned char* pshdrs = sd->section_headers_data
- + This::shdr_size * shndx;
+ + This::shdr_size * shndx;
typename This::Shdr shdr(pshdrs);
- return shdr.get_sh_entsize();
+ return shdr.get_sh_entsize();
}
// Write out the local symbols.
unsigned char* dyn_oview = NULL;
if (dyn_output_size > 0)
dyn_oview = of->get_output_view(this->local_dynsym_offset_,
- dyn_output_size);
+ dyn_output_size);
const Output_sections out_sections(this->output_sections());
// Write the symbol to the output symbol table.
if (lv.has_output_symtab_entry())
- {
- elfcpp::Sym_write<size, big_endian> osym(ov);
-
- gold_assert(isym.get_st_name() < strtab_size);
- const char* name = pnames + isym.get_st_name();
- osym.put_st_name(sympool->get_offset(name));
- osym.put_st_value(this->local_values_[i].value(this, 0));
- osym.put_st_size(isym.get_st_size());
- osym.put_st_info(isym.get_st_info());
- osym.put_st_other(isym.get_st_other());
- osym.put_st_shndx(st_shndx);
-
- ov += sym_size;
- }
+ {
+ elfcpp::Sym_write<size, big_endian> osym(ov);
+
+ gold_assert(isym.get_st_name() < strtab_size);
+ const char* name = pnames + isym.get_st_name();
+ osym.put_st_name(sympool->get_offset(name));
+ osym.put_st_value(this->local_values_[i].value(this, 0));
+ osym.put_st_size(isym.get_st_size());
+ osym.put_st_info(isym.get_st_info());
+ osym.put_st_other(isym.get_st_other());
+ osym.put_st_shndx(st_shndx);
+
+ ov += sym_size;
+ }
// Write the symbol to the output dynamic symbol table.
if (lv.has_output_dynsym_entry())
- {
- gold_assert(dyn_ov < dyn_oview + dyn_output_size);
- elfcpp::Sym_write<size, big_endian> osym(dyn_ov);
-
- gold_assert(isym.get_st_name() < strtab_size);
- const char* name = pnames + isym.get_st_name();
- osym.put_st_name(dynpool->get_offset(name));
- osym.put_st_value(this->local_values_[i].value(this, 0));
- osym.put_st_size(isym.get_st_size());
- osym.put_st_info(isym.get_st_info());
- osym.put_st_other(isym.get_st_other());
- osym.put_st_shndx(st_shndx);
-
- dyn_ov += sym_size;
- }
+ {
+ gold_assert(dyn_ov < dyn_oview + dyn_output_size);
+ elfcpp::Sym_write<size, big_endian> osym(dyn_ov);
+
+ gold_assert(isym.get_st_name() < strtab_size);
+ const char* name = pnames + isym.get_st_name();
+ osym.put_st_name(dynpool->get_offset(name));
+ osym.put_st_value(this->local_values_[i].value(this, 0));
+ osym.put_st_size(isym.get_st_size());
+ osym.put_st_info(isym.get_st_info());
+ osym.put_st_other(isym.get_st_other());
+ osym.put_st_shndx(st_shndx);
+
+ dyn_ov += sym_size;
+ }
}
{
gold_assert(dyn_ov - dyn_oview == dyn_output_size);
of->write_output_view(this->local_dynsym_offset_, dyn_output_size,
- dyn_oview);
+ dyn_oview);
}
}
&& static_cast<off_t>(sym.get_st_value()) <= offset
&& (static_cast<off_t>(sym.get_st_value() + sym.get_st_size())
> offset))
- {
- if (sym.get_st_name() > names_size)
+ {
+ if (sym.get_st_name() > names_size)
info->enclosing_symbol_name = "(invalid)";
else
- {
- info->enclosing_symbol_name = symbol_names + sym.get_st_name();
- if (parameters->options().do_demangle())
- {
- char* demangled_name = cplus_demangle(
- info->enclosing_symbol_name.c_str(),
- DMGL_ANSI | DMGL_PARAMS);
- if (demangled_name != NULL)
- {
- info->enclosing_symbol_name.assign(demangled_name);
- free(demangled_name);
- }
- }
- }
+ {
+ info->enclosing_symbol_name = symbol_names + sym.get_st_name();
+ if (parameters->options().do_demangle())
+ {
+ char* demangled_name = cplus_demangle(
+ info->enclosing_symbol_name.c_str(),
+ DMGL_ANSI | DMGL_PARAMS);
+ if (demangled_name != NULL)
+ {
+ info->enclosing_symbol_name.assign(demangled_name);
+ free(demangled_name);
+ }
+ }
+ }
return true;
- }
+ }
}
return false;
++p)
{
if (p->second.contents != NULL)
- {
- delete[] p->second.contents;
- p->second.contents = NULL;
- }
+ {
+ delete[] p->second.contents;
+ p->second.contents = NULL;
+ }
}
}
off_t offset, const elfcpp::Ehdr<size, big_endian>& ehdr,
bool* punconfigured)
{
- Target* target = select_target(ehdr.get_e_machine(), size, big_endian,
+ Target* target = select_target(input_file, offset,
+ ehdr.get_e_machine(), size, big_endian,
ehdr.get_e_ident()[elfcpp::EI_OSABI],
ehdr.get_e_ident()[elfcpp::EI_ABIVERSION]);
if (target == NULL)
bool big_endian = false;
int size = 0;
if (!elfcpp::Elf_recognizer::is_valid_header(p, bytes, &size,
- &big_endian, &error))
+ &big_endian, &error))
{
gold_error(_("%s: %s"), name.c_str(), error.c_str());
return NULL;
// parameters.cc -- general parameters for a link using gold
-// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012
+// Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
gold_assert(endianness == General_options::ENDIANNESS_LITTLE);
big_endian = false;;
}
-
+
if (this->target().is_big_endian() != big_endian)
gold_error(_("input file does not match -EB/EL option"));
}
else
is_big_endian = GOLD_DEFAULT_BIG_ENDIAN;
- Target* target = select_target(elfcpp::GOLD_DEFAULT_MACHINE,
+ Target* target = select_target(NULL, 0,
+ elfcpp::GOLD_DEFAULT_MACHINE,
GOLD_DEFAULT_SIZE,
is_big_endian,
elfcpp::GOLD_DEFAULT_OSABI,
// powerpc.cc -- powerpc target support for gold.
-// Copyright 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+// Copyright 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
// Written by David S. Miller <davem@davemloft.net>
// and David Edelsohn <edelsohn@gnu.org>
{
}
- // Process the relocations to determine unreferenced sections for
+ // Process the relocations to determine unreferenced sections for
// garbage collection.
void
gc_process_relocs(Symbol_table* symtab,
- Layout* layout,
- Sized_relobj_file<size, big_endian>* object,
- unsigned int data_shndx,
- unsigned int sh_type,
- const unsigned char* prelocs,
- size_t reloc_count,
- Output_section* output_section,
- bool needs_special_offset_handling,
- size_t local_symbol_count,
- const unsigned char* plocal_symbols);
+ Layout* layout,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols);
// Scan the relocations to look for symbol adjustments.
void
inline bool
local_reloc_may_be_function_pointer(Symbol_table* , Layout* ,
Target_powerpc* ,
- Sized_relobj_file<size, big_endian>* ,
- unsigned int ,
- Output_section* ,
- const elfcpp::Rela<size, big_endian>& ,
+ Sized_relobj_file<size, big_endian>* ,
unsigned int ,
- const elfcpp::Sym<size, big_endian>&)
+ Output_section* ,
+ const elfcpp::Rela<size, big_endian>& ,
+ unsigned int ,
+ const elfcpp::Sym<size, big_endian>&)
{ return false; }
inline bool
global_reloc_may_be_function_pointer(Symbol_table* , Layout* ,
Target_powerpc* ,
- Sized_relobj_file<size, big_endian>* ,
- unsigned int ,
- Output_section* ,
- const elfcpp::Rela<size,
+ Sized_relobj_file<size, big_endian>* ,
+ unsigned int ,
+ Output_section* ,
+ const elfcpp::Rela<size,
big_endian>& ,
unsigned int , Symbol*)
{ return false; }
inline void
relocate_tls(const Relocate_info<size, big_endian>*,
Target_powerpc* target,
- size_t relnum, const elfcpp::Rela<size, big_endian>&,
+ size_t relnum, const elfcpp::Rela<size, big_endian>&,
unsigned int r_type, const Sized_symbol<size>*,
const Symbol_value<size>*,
unsigned char*,
// Copy a relocation against a global symbol.
void
copy_reloc(Symbol_table* symtab, Layout* layout,
- Sized_relobj_file<size, big_endian>* object,
+ Sized_relobj_file<size, big_endian>* object,
unsigned int shndx, Output_section* output_section,
Symbol* sym, const elfcpp::Rela<size, big_endian>& reloc)
{
0x10000000, // default_text_segment_address
64 * 1024, // abi_pagesize (overridable by -z max-page-size)
4 * 1024, // common_pagesize (overridable by -z common-page-size)
+ false, // isolate_execinstr
+ 0, // rosegment_gap
elfcpp::SHN_UNDEF, // small_common_shndx
elfcpp::SHN_UNDEF, // large_common_shndx
0, // small_common_section_flags
0x10000000, // default_text_segment_address
64 * 1024, // abi_pagesize (overridable by -z max-page-size)
4 * 1024, // common_pagesize (overridable by -z common-page-size)
+ false, // isolate_execinstr
+ 0, // rosegment_gap
elfcpp::SHN_UNDEF, // small_common_shndx
elfcpp::SHN_UNDEF, // large_common_shndx
0, // small_common_section_flags
0x10000000, // default_text_segment_address
64 * 1024, // abi_pagesize (overridable by -z max-page-size)
8 * 1024, // common_pagesize (overridable by -z common-page-size)
+ false, // isolate_execinstr
+ 0, // rosegment_gap
elfcpp::SHN_UNDEF, // small_common_shndx
elfcpp::SHN_UNDEF, // large_common_shndx
0, // small_common_section_flags
0x10000000, // default_text_segment_address
64 * 1024, // abi_pagesize (overridable by -z max-page-size)
8 * 1024, // common_pagesize (overridable by -z common-page-size)
+ false, // isolate_execinstr
+ 0, // rosegment_gap
elfcpp::SHN_UNDEF, // small_common_shndx
elfcpp::SHN_UNDEF, // large_common_shndx
0, // small_common_section_flags
static const unsigned int std_r2_40r1 = 0xf8410028; /* std %r2,40(%r1) */
static const unsigned int ld_r11_0r12 = 0xe96c0000; /* ld %r11,xxx+0@l(%r12) */
static const unsigned int ld_r2_0r12 = 0xe84c0000; /* ld %r2,xxx+8@l(%r12) */
- /* ld %r11,xxx+16@l(%r12) */
+ /* ld %r11,xxx+16@l(%r12) */
// Write out the PLT.
// executable), we need to create a dynamic relocation for
// this location.
if (parameters->options().output_is_position_independent())
- {
- Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ {
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
check_non_pic(object, r_type);
- if (lsym.get_st_type() != elfcpp::STT_SECTION)
- {
- unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
- rela_dyn->add_local(object, r_sym, r_type, output_section,
+ if (lsym.get_st_type() != elfcpp::STT_SECTION)
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ rela_dyn->add_local(object, r_sym, r_type, output_section,
data_shndx, reloc.get_r_offset(),
reloc.get_r_addend());
- }
- else
- {
+ }
+ else
+ {
unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
- gold_assert(lsym.get_st_value() == 0);
- rela_dyn->add_local_relative(object, r_sym, r_type,
+ gold_assert(lsym.get_st_value() == 0);
+ rela_dyn->add_local_relative(object, r_sym, r_type,
output_section, data_shndx,
reloc.get_r_offset(),
reloc.get_r_addend(), false);
- }
- }
+ }
+ }
break;
case elfcpp::R_POWERPC_REL24:
case elfcpp::R_PPC64_TOC16_DS:
case elfcpp::R_PPC64_TOC16_LO_DS:
{
- // The symbol requires a GOT entry.
- Output_data_got<size, big_endian>* got;
+ // The symbol requires a GOT entry.
+ Output_data_got<size, big_endian>* got;
unsigned int r_sym;
got = target->got_section(symtab, layout);
elfcpp::R_POWERPC_RELATIVE,
got, off, 0, false);
}
- }
+ }
else
got->add_local(object, r_sym, GOT_TYPE_STANDARD);
}
// if the symbol is defined in the output file and is protected
// or hidden.
if (gsym->is_defined()
- && !gsym->is_from_dynobj()
- && !gsym->is_preemptible())
+ && !gsym->is_from_dynobj()
+ && !gsym->is_preemptible())
break;
target->make_plt_entry(symtab, layout, gsym);
break;
case elfcpp::R_POWERPC_ADDR32:
case elfcpp::R_PPC64_ADDR64:
{
- // Make a PLT entry if necessary.
- if (gsym->needs_plt_entry())
- {
- target->make_plt_entry(symtab, layout, gsym);
- // Since this is not a PC-relative relocation, we may be
- // taking the address of a function. In that case we need to
- // set the entry in the dynamic symbol table to the address of
- // the PLT entry.
- if (gsym->is_from_dynobj() && !parameters->options().shared())
- gsym->set_needs_dynsym_value();
- }
- // Make a dynamic relocation if necessary.
- if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
- {
- if (gsym->may_need_copy_reloc())
- {
- target->copy_reloc(symtab, layout, object,
- data_shndx, output_section, gsym, reloc);
- }
- else if ((r_type == elfcpp::R_POWERPC_ADDR32
+ // Make a PLT entry if necessary.
+ if (gsym->needs_plt_entry())
+ {
+ target->make_plt_entry(symtab, layout, gsym);
+ // Since this is not a PC-relative relocation, we may be
+ // taking the address of a function. In that case we need to
+ // set the entry in the dynamic symbol table to the address of
+ // the PLT entry.
+ if (gsym->is_from_dynobj() && !parameters->options().shared())
+ gsym->set_needs_dynsym_value();
+ }
+ // Make a dynamic relocation if necessary.
+ if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
+ {
+ if (gsym->may_need_copy_reloc())
+ {
+ target->copy_reloc(symtab, layout, object,
+ data_shndx, output_section, gsym, reloc);
+ }
+ else if ((r_type == elfcpp::R_POWERPC_ADDR32
|| r_type == elfcpp::R_PPC64_ADDR64)
- && gsym->can_use_relative_reloc(false))
- {
- Reloc_section* rela_dyn = target->rela_dyn_section(layout);
- rela_dyn->add_global_relative(gsym, elfcpp::R_POWERPC_RELATIVE,
+ && gsym->can_use_relative_reloc(false))
+ {
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ rela_dyn->add_global_relative(gsym, elfcpp::R_POWERPC_RELATIVE,
output_section, object,
data_shndx, reloc.get_r_offset(),
reloc.get_r_addend(), false);
- }
- else
- {
- Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ }
+ else
+ {
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
check_non_pic(object, r_type);
if (gsym->is_from_dynobj()
data_shndx,
reloc.get_r_offset(),
reloc.get_r_addend(), false);
- }
- }
+ }
+ }
}
break;
case elfcpp::R_PPC64_TOC16_DS:
case elfcpp::R_PPC64_TOC16_LO_DS:
{
- // The symbol requires a GOT entry.
- Output_data_got<size, big_endian>* got;
+ // The symbol requires a GOT entry.
+ Output_data_got<size, big_endian>* got;
got = target->got_section(symtab, layout);
- if (gsym->final_value_is_known())
- got->add_global(gsym, GOT_TYPE_STANDARD);
- else
- {
- // If this symbol is not fully resolved, we need to add a
- // dynamic relocation for it.
- Reloc_section* rela_dyn = target->rela_dyn_section(layout);
- if (gsym->is_from_dynobj()
- || gsym->is_undefined()
- || gsym->is_preemptible())
- got->add_global_with_rel(gsym, GOT_TYPE_STANDARD, rela_dyn,
+ if (gsym->final_value_is_known())
+ got->add_global(gsym, GOT_TYPE_STANDARD);
+ else
+ {
+ // If this symbol is not fully resolved, we need to add a
+ // dynamic relocation for it.
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ if (gsym->is_from_dynobj()
+ || gsym->is_undefined()
+ || gsym->is_preemptible())
+ got->add_global_with_rel(gsym, GOT_TYPE_STANDARD, rela_dyn,
elfcpp::R_POWERPC_GLOB_DAT);
- else if (!gsym->has_got_offset(GOT_TYPE_STANDARD))
- {
+ else if (!gsym->has_got_offset(GOT_TYPE_STANDARD))
+ {
unsigned int off = got->add_constant(0);
gsym->set_got_offset(GOT_TYPE_STANDARD, off);
rela_dyn->add_global_relative(gsym, elfcpp::R_POWERPC_RELATIVE,
got, off, 0, false);
}
- }
+ }
}
break;
case elfcpp::R_PPC64_GOT16_DS:
case elfcpp::R_PPC64_GOT16_LO_DS:
if (gsym != NULL)
- {
- gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD));
- got_offset = gsym->got_offset(GOT_TYPE_STANDARD);
- }
+ {
+ gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD));
+ got_offset = gsym->got_offset(GOT_TYPE_STANDARD);
+ }
else
- {
- unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
- gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD));
- got_offset = object->local_got_offset(r_sym, GOT_TYPE_STANDARD);
- }
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
+ gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD));
+ got_offset = object->local_got_offset(r_sym, GOT_TYPE_STANDARD);
+ }
break;
// R_PPC_PLTREL24 is rather special. If non-zero,
- // the addend specifies the GOT pointer offset within .got2.
+ // the addend specifies the GOT pointer offset within .got2.
case elfcpp::R_PPC_PLTREL24:
if (addend >= 32768)
{
: (big_endian ? "elf32ppc" : "elf32lppc")))
{ }
- Target* do_recognize(int machine, int, int)
+ virtual Target*
+ do_recognize(Input_file*, off_t, int machine, int, int)
{
switch (size)
{
return this->instantiate_target();
}
- Target* do_instantiate_target()
+ virtual Target*
+ do_instantiate_target()
{ return new Target_powerpc<size, big_endian>(); }
};
{
}
- // Process the relocations to determine unreferenced sections for
+ // Process the relocations to determine unreferenced sections for
// garbage collection.
void
gc_process_relocs(Symbol_table* symtab,
- Layout* layout,
- Sized_relobj_file<size, big_endian>* object,
- unsigned int data_shndx,
- unsigned int sh_type,
- const unsigned char* prelocs,
- size_t reloc_count,
- Output_section* output_section,
- bool needs_special_offset_handling,
- size_t local_symbol_count,
- const unsigned char* plocal_symbols);
+ Layout* layout,
+ Sized_relobj_file<size, big_endian>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols);
// Scan the relocations to look for symbol adjustments.
void
inline bool
local_reloc_may_be_function_pointer(Symbol_table* , Layout* ,
- Target_sparc* ,
- Sized_relobj_file<size, big_endian>* ,
- unsigned int ,
- Output_section* ,
- const elfcpp::Rela<size, big_endian>& ,
+ Target_sparc* ,
+ Sized_relobj_file<size, big_endian>* ,
unsigned int ,
- const elfcpp::Sym<size, big_endian>&)
+ Output_section* ,
+ const elfcpp::Rela<size, big_endian>& ,
+ unsigned int ,
+ const elfcpp::Sym<size, big_endian>&)
{ return false; }
inline bool
global_reloc_may_be_function_pointer(Symbol_table* , Layout* ,
- Target_sparc* ,
- Sized_relobj_file<size, big_endian>* ,
- unsigned int ,
- Output_section* ,
- const elfcpp::Rela<size,
- big_endian>& ,
- unsigned int , Symbol*)
+ Target_sparc* ,
+ Sized_relobj_file<size, big_endian>* ,
+ unsigned int ,
+ Output_section* ,
+ const elfcpp::Rela<size,
+ big_endian>& ,
+ unsigned int , Symbol*)
{ return false; }
// Do a TLS relocation.
inline void
relocate_tls(const Relocate_info<size, big_endian>*, Target_sparc* target,
- size_t relnum, const elfcpp::Rela<size, big_endian>&,
+ size_t relnum, const elfcpp::Rela<size, big_endian>&,
unsigned int r_type, const Sized_symbol<size>*,
const Symbol_value<size>*,
unsigned char*,
// Copy a relocation against a global symbol.
void
copy_reloc(Symbol_table* symtab, Layout* layout,
- Sized_relobj_file<size, big_endian>* object,
+ Sized_relobj_file<size, big_endian>* object,
unsigned int shndx, Output_section* output_section,
Symbol* sym, const elfcpp::Rela<size, big_endian>& reloc)
{
0x00010000, // default_text_segment_address
64 * 1024, // abi_pagesize (overridable by -z max-page-size)
8 * 1024, // common_pagesize (overridable by -z common-page-size)
+ false, // isolate_execinstr
+ 0, // rosegment_gap
elfcpp::SHN_UNDEF, // small_common_shndx
elfcpp::SHN_UNDEF, // large_common_shndx
0, // small_common_section_flags
0x100000, // default_text_segment_address
64 * 1024, // abi_pagesize (overridable by -z max-page-size)
8 * 1024, // common_pagesize (overridable by -z common-page-size)
+ false, // isolate_execinstr
+ 0, // rosegment_gap
elfcpp::SHN_UNDEF, // small_common_shndx
elfcpp::SHN_UNDEF, // large_common_shndx
0, // small_common_section_flags
int flags = Scan::get_reference_flags(r_type);
if (flags & Symbol::TLS_REF)
gold_error(_("%s: unsupported TLS reloc %u for IFUNC symbol"),
- object->name().c_str(), r_type);
+ object->name().c_str(), r_type);
return flags != 0;
}
// an R_SPARC_RELATIVE relocation so the dynamic loader can
// relocate it easily.
if (parameters->options().output_is_position_independent())
- {
- Reloc_section* rela_dyn = target->rela_dyn_section(layout);
- unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
- rela_dyn->add_local_relative(object, r_sym, elfcpp::R_SPARC_RELATIVE,
+ {
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ rela_dyn->add_local_relative(object, r_sym, elfcpp::R_SPARC_RELATIVE,
output_section, data_shndx,
reloc.get_r_offset(),
reloc.get_r_addend(), is_ifunc);
- }
+ }
break;
case elfcpp::R_SPARC_HIX22:
// executable), we need to create a dynamic relocation for
// this location.
if (parameters->options().output_is_position_independent())
- {
- Reloc_section* rela_dyn = target->rela_dyn_section(layout);
- unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ {
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
check_non_pic(object, r_type);
- if (lsym.get_st_type() != elfcpp::STT_SECTION)
- {
- rela_dyn->add_local(object, r_sym, orig_r_type, output_section,
+ if (lsym.get_st_type() != elfcpp::STT_SECTION)
+ {
+ rela_dyn->add_local(object, r_sym, orig_r_type, output_section,
data_shndx, reloc.get_r_offset(),
reloc.get_r_addend());
- }
- else
- {
- gold_assert(lsym.get_st_value() == 0);
+ }
+ else
+ {
+ gold_assert(lsym.get_st_value() == 0);
rela_dyn->add_symbolless_local_addend(object, r_sym, orig_r_type,
output_section, data_shndx,
reloc.get_r_offset(),
reloc.get_r_addend());
- }
- }
+ }
+ }
break;
case elfcpp::R_SPARC_WDISP30:
case elfcpp::R_SPARC_GOT13:
case elfcpp::R_SPARC_GOT22:
{
- // The symbol requires a GOT entry.
- Output_data_got<size, big_endian>* got;
- unsigned int r_sym;
+ // The symbol requires a GOT entry.
+ Output_data_got<size, big_endian>* got;
+ unsigned int r_sym;
got = target->got_section(symtab, layout);
r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
{
bool output_is_shared = parameters->options().shared();
const tls::Tls_optimization optimized_type
- = optimize_tls_reloc(!output_is_shared, r_type);
+ = optimize_tls_reloc(!output_is_shared, r_type);
switch (r_type)
{
case elfcpp::R_SPARC_TLS_GD_HI22: // Global-dynamic
case elfcpp::R_SPARC_TLS_GD_CALL:
if (optimized_type == tls::TLSOPT_NONE)
{
- // Create a pair of GOT entries for the module index and
- // dtv-relative offset.
- Output_data_got<size, big_endian>* got
- = target->got_section(symtab, layout);
- unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ // Create a pair of GOT entries for the module index and
+ // dtv-relative offset.
+ Output_data_got<size, big_endian>* got
+ = target->got_section(symtab, layout);
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
unsigned int shndx = lsym.get_st_shndx();
bool is_ordinary;
shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
object->error(_("local symbol %u has bad shndx %u"),
r_sym, shndx);
else
- got->add_local_pair_with_rel(object, r_sym,
+ got->add_local_pair_with_rel(object, r_sym,
lsym.get_st_shndx(),
GOT_TYPE_TLS_PAIR,
target->rela_dyn_section(layout),
layout->set_has_static_tls();
if (output_is_shared)
{
- // We need to create a dynamic relocation.
- gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION);
- unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
- Reloc_section* rela_dyn = target->rela_dyn_section(layout);
- rela_dyn->add_symbolless_local_addend(object, r_sym, r_type,
+ // We need to create a dynamic relocation.
+ gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION);
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ rela_dyn->add_symbolless_local_addend(object, r_sym, r_type,
output_section, data_shndx,
reloc.get_r_offset(), 0);
}
// if the symbol is defined in the output file and is protected
// or hidden.
if (gsym->is_defined()
- && !gsym->is_from_dynobj()
- && !gsym->is_preemptible())
+ && !gsym->is_from_dynobj()
+ && !gsym->is_preemptible())
break;
target->make_plt_entry(symtab, layout, gsym);
break;
case elfcpp::R_SPARC_6:
case elfcpp::R_SPARC_5:
{
- // Make a PLT entry if necessary.
- if (gsym->needs_plt_entry())
- {
- target->make_plt_entry(symtab, layout, gsym);
- // Since this is not a PC-relative relocation, we may be
- // taking the address of a function. In that case we need to
- // set the entry in the dynamic symbol table to the address of
- // the PLT entry.
- if (gsym->is_from_dynobj() && !parameters->options().shared())
- gsym->set_needs_dynsym_value();
- }
- // Make a dynamic relocation if necessary.
- if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
- {
+ // Make a PLT entry if necessary.
+ if (gsym->needs_plt_entry())
+ {
+ target->make_plt_entry(symtab, layout, gsym);
+ // Since this is not a PC-relative relocation, we may be
+ // taking the address of a function. In that case we need to
+ // set the entry in the dynamic symbol table to the address of
+ // the PLT entry.
+ if (gsym->is_from_dynobj() && !parameters->options().shared())
+ gsym->set_needs_dynsym_value();
+ }
+ // Make a dynamic relocation if necessary.
+ if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
+ {
unsigned int r_off = reloc.get_r_offset();
// The assembler can sometimes emit unaligned relocations
- // for dwarf2 cfi directives.
+ // for dwarf2 cfi directives.
switch (r_type)
{
case elfcpp::R_SPARC_16:
break;
}
- if (gsym->may_need_copy_reloc())
- {
- target->copy_reloc(symtab, layout, object,
- data_shndx, output_section, gsym, reloc);
- }
+ if (gsym->may_need_copy_reloc())
+ {
+ target->copy_reloc(symtab, layout, object,
+ data_shndx, output_section, gsym, reloc);
+ }
else if (((size == 64 && r_type == elfcpp::R_SPARC_64)
|| (size == 32 && r_type == elfcpp::R_SPARC_32))
&& gsym->type() == elfcpp::STT_GNU_IFUNC
reloc.get_r_offset(),
reloc.get_r_addend());
}
- else if ((r_type == elfcpp::R_SPARC_32
+ else if ((r_type == elfcpp::R_SPARC_32
|| r_type == elfcpp::R_SPARC_64)
- && gsym->can_use_relative_reloc(false))
- {
- Reloc_section* rela_dyn = target->rela_dyn_section(layout);
- rela_dyn->add_global_relative(gsym, elfcpp::R_SPARC_RELATIVE,
+ && gsym->can_use_relative_reloc(false))
+ {
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ rela_dyn->add_global_relative(gsym, elfcpp::R_SPARC_RELATIVE,
output_section, object,
data_shndx, reloc.get_r_offset(),
reloc.get_r_addend(), is_ifunc);
- }
- else
- {
- Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ }
+ else
+ {
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
check_non_pic(object, r_type);
if (gsym->is_from_dynobj()
object, data_shndx,
reloc.get_r_offset(),
reloc.get_r_addend());
- }
- }
+ }
+ }
}
break;
case elfcpp::R_SPARC_GOTDATA_OP_HIX22:
case elfcpp::R_SPARC_GOTDATA_OP_LOX10:
if (gsym->is_defined()
- && !gsym->is_from_dynobj()
- && !gsym->is_preemptible()
+ && !gsym->is_from_dynobj()
+ && !gsym->is_preemptible()
&& !is_ifunc)
{
// We will optimize this into a GOT relative relocation
case elfcpp::R_SPARC_GOT13:
case elfcpp::R_SPARC_GOT22:
{
- // The symbol requires a GOT entry.
- Output_data_got<size, big_endian>* got;
+ // The symbol requires a GOT entry.
+ Output_data_got<size, big_endian>* got;
got = target->got_section(symtab, layout);
- if (gsym->final_value_is_known())
+ if (gsym->final_value_is_known())
{
// For a STT_GNU_IFUNC symbol we want the PLT address.
if (gsym->type() == elfcpp::STT_GNU_IFUNC)
else
got->add_global(gsym, GOT_TYPE_STANDARD);
}
- else
- {
- // If this symbol is not fully resolved, we need to add a
- // GOT entry with a dynamic relocation.
+ else
+ {
+ // If this symbol is not fully resolved, we need to add a
+ // GOT entry with a dynamic relocation.
bool is_ifunc = gsym->type() == elfcpp::STT_GNU_IFUNC;
// Use a GLOB_DAT rather than a RELATIVE reloc if:
//
// 3) This is a STT_GNU_IFUNC symbol in position dependent
// code, again so that function address comparisons work.
- Reloc_section* rela_dyn = target->rela_dyn_section(layout);
- if (gsym->is_from_dynobj()
- || gsym->is_undefined()
- || gsym->is_preemptible()
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ if (gsym->is_from_dynobj()
+ || gsym->is_undefined()
+ || gsym->is_preemptible()
|| (gsym->visibility() == elfcpp::STV_PROTECTED
&& parameters->options().shared())
|| (gsym->type() == elfcpp::STT_GNU_IFUNC
got->add_global_with_rel(gsym, GOT_TYPE_STANDARD, rela_dyn,
r_type);
}
- else if (!gsym->has_got_offset(GOT_TYPE_STANDARD))
- {
+ else if (!gsym->has_got_offset(GOT_TYPE_STANDARD))
+ {
unsigned int off = got->add_constant(0);
gsym->set_got_offset(GOT_TYPE_STANDARD, off);
rela_dyn->add_global_relative(gsym, elfcpp::R_SPARC_RELATIVE,
got, off, 0, is_ifunc);
}
- }
+ }
}
break;
{
const bool is_final = gsym->final_value_is_known();
const tls::Tls_optimization optimized_type
- = optimize_tls_reloc(is_final, r_type);
+ = optimize_tls_reloc(is_final, r_type);
switch (r_type)
{
case elfcpp::R_SPARC_TLS_GD_HI22: // Global-dynamic
case elfcpp::R_SPARC_TLS_GD_CALL:
if (optimized_type == tls::TLSOPT_NONE)
{
- // Create a pair of GOT entries for the module index and
- // dtv-relative offset.
- Output_data_got<size, big_endian>* got
- = target->got_section(symtab, layout);
- got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_PAIR,
+ // Create a pair of GOT entries for the module index and
+ // dtv-relative offset.
+ Output_data_got<size, big_endian>* got
+ = target->got_section(symtab, layout);
+ got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_PAIR,
target->rela_dyn_section(layout),
(size == 64
? elfcpp::R_SPARC_TLS_DTPMOD64
}
else if (optimized_type == tls::TLSOPT_TO_IE)
{
- // Create a GOT entry for the tp-relative offset.
- Output_data_got<size, big_endian>* got
- = target->got_section(symtab, layout);
- got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
+ // Create a GOT entry for the tp-relative offset.
+ Output_data_got<size, big_endian>* got
+ = target->got_section(symtab, layout);
+ got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
target->rela_dyn_section(layout),
(size == 64 ?
elfcpp::R_SPARC_TLS_TPOFF64 :
case elfcpp::R_SPARC_GOT13:
case elfcpp::R_SPARC_GOT22:
if (gsym != NULL)
- {
- gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD));
- got_offset = gsym->got_offset(GOT_TYPE_STANDARD);
- }
+ {
+ gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD));
+ got_offset = gsym->got_offset(GOT_TYPE_STANDARD);
+ }
else
- {
- unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
- gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD));
- got_offset = object->local_got_offset(r_sym, GOT_TYPE_STANDARD);
- }
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
+ gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD));
+ got_offset = object->local_got_offset(r_sym, GOT_TYPE_STANDARD);
+ }
break;
default:
if (rela.get_r_offset() & 0x1)
{
// The assembler can sometimes emit unaligned relocations
- // for dwarf2 cfi directives.
+ // for dwarf2 cfi directives.
Reloc::ua16(view, object, psymval, addend);
}
else
if (rela.get_r_offset() & 0x3)
{
// The assembler can sometimes emit unaligned relocations
- // for dwarf2 cfi directives.
+ // for dwarf2 cfi directives.
Reloc::ua32(view, object, psymval, addend);
}
else
if (rela.get_r_offset() & 0x7)
{
// The assembler can sometimes emit unaligned relocations
- // for dwarf2 cfi directives.
+ // for dwarf2 cfi directives.
Reloc::ua64(view, object, psymval, addend);
}
else
break;
}
else
- {
- unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE
- ? GOT_TYPE_TLS_OFFSET
- : GOT_TYPE_TLS_PAIR);
- if (gsym != NULL)
- {
- gold_assert(gsym->has_got_offset(got_type));
- value = gsym->got_offset(got_type);
- }
- else
- {
- unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
- gold_assert(object->local_has_got_offset(r_sym, got_type));
- value = object->local_got_offset(r_sym, got_type);
- }
- if (optimized_type == tls::TLSOPT_TO_IE)
+ {
+ unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE
+ ? GOT_TYPE_TLS_OFFSET
+ : GOT_TYPE_TLS_PAIR);
+ if (gsym != NULL)
+ {
+ gold_assert(gsym->has_got_offset(got_type));
+ value = gsym->got_offset(got_type);
+ }
+ else
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
+ gold_assert(object->local_has_got_offset(r_sym, got_type));
+ value = object->local_got_offset(r_sym, got_type);
+ }
+ if (optimized_type == tls::TLSOPT_TO_IE)
{
Insntype* wv = reinterpret_cast<Insntype*>(view);
Insntype val;
elfcpp::Swap<32, true>::writeval(wv, 0x9001c008);
break;
}
- break;
+ break;
}
- else if (optimized_type == tls::TLSOPT_NONE)
- {
+ else if (optimized_type == tls::TLSOPT_NONE)
+ {
switch (r_type)
{
case elfcpp::R_SPARC_TLS_GD_HI22:
break;
}
break;
- }
- }
+ }
+ }
gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
_("unsupported reloc %u"),
r_type);
break;
}
else if (optimized_type == tls::TLSOPT_NONE)
- {
- // Relocate the field with the offset of the GOT entry for
- // the module index.
- unsigned int got_offset;
+ {
+ // Relocate the field with the offset of the GOT entry for
+ // the module index.
+ unsigned int got_offset;
got_offset = target->got_mod_index_entry(NULL, NULL, NULL);
switch (r_type)
}
break;
}
- break;
- }
+ break;
+ }
gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
_("unsupported reloc %u"),
r_type);
elfcpp::Elf_Half machine = ehdr.get_e_machine();
elfcpp::Elf_Word flags = ehdr.get_e_flags();
elfcpp::Elf_Word omm, mm;
-
+
switch (machine)
{
case elfcpp::EM_SPARC32PLUS:
(size == 64 ? "elf64_sparc" : "elf32_sparc"))
{ }
- Target* do_recognize(int machine, int, int)
+ virtual Target*
+ do_recognize(Input_file*, off_t, int machine, int, int)
{
switch (size)
{
return this->instantiate_target();
}
- Target* do_instantiate_target()
+ virtual Target*
+ do_instantiate_target()
{ return new Target_sparc<size, big_endian>(); }
};
// target-select.cc -- select a target for an object file
-// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012
+// Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
// Find the target for an ELF file.
Target*
-select_target(int machine, int size, bool is_big_endian, int osabi,
- int abiversion)
+select_target(Input_file* input_file, off_t offset,
+ int machine, int size, bool is_big_endian,
+ int osabi, int abiversion)
{
for (Target_selector* p = target_selectors; p != NULL; p = p->next())
{
&& p->get_size() == size
&& (p->is_big_endian() ? is_big_endian : !is_big_endian))
{
- Target* ret = p->recognize(machine, osabi, abiversion);
+ Target* ret = p->recognize(input_file, offset,
+ machine, osabi, abiversion);
if (ret != NULL)
return ret;
}
// target-select.h -- select a target for an object file -*- C++ -*-
-// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012
+// Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
namespace gold
{
+class Input_file;
class Target;
class Target_selector;
// If we can handle this target, return a pointer to a target
// structure. The size and endianness are known.
Target*
- recognize(int machine, int osabi, int abiversion)
- { return this->do_recognize(machine, osabi, abiversion); }
+ recognize(Input_file* input_file, off_t offset,
+ int machine, int osabi, int abiversion)
+ { return this->do_recognize(input_file, offset, machine, osabi, abiversion); }
// If NAME matches the target, return a pointer to a target
// structure.
// checks, or to check for multiple machine codes if the machine_
// field is EM_NONE.
virtual Target*
- do_recognize(int, int, int)
+ do_recognize(Input_file*, off_t, int, int, int)
{ return this->instantiate_target(); }
// Recognize a target by name. When this is called we already know
// Select the target for an ELF file.
extern Target*
-select_target(int machine, int size, bool big_endian, int osabi,
+select_target(Input_file*, off_t,
+ int machine, int size, bool big_endian, int osabi,
int abiversion);
// Select a target using a BFD name.
this->abi_pagesize());
}
+ // Return whether PF_X segments must contain nothing but the contents of
+ // SHF_EXECINSTR sections (no non-executable data, no headers).
+ bool
+ isolate_execinstr() const
+ { return this->pti_->isolate_execinstr; }
+
+ uint64_t
+ rosegment_gap() const
+ { return this->pti_->rosegment_gap; }
+
// If we see some object files with .note.GNU-stack sections, and
// some objects files without them, this returns whether we should
// consider the object files without them to imply that the stack
return pass < 2;
return this->do_relax(pass, input_objects, symtab, layout, task);
- }
+ }
// Return the target-specific name of attributes section. This is
// NULL if a target does not use attributes section or if it uses
{
return ((this->pti_->attributes_section != NULL
&& strcmp(name, this->pti_->attributes_section) == 0)
- || strcmp(name, ".gnu.attributes") == 0);
+ || strcmp(name, ".gnu.attributes") == 0);
}
// Return a bit mask of argument types for attribute with TAG.
// which may be used for expensive, target-specific initialization.
void
select_as_default_target()
- { this->do_select_as_default_target(); }
+ { this->do_select_as_default_target(); }
// Return the value to store in the EI_OSABI field in the ELF
// header.
uint64_t abi_pagesize;
// The common page size used by actual implementations.
uint64_t common_pagesize;
+ // Whether PF_X segments must contain nothing but the contents of
+ // SHF_EXECINSTR sections (no non-executable data, no headers).
+ bool isolate_execinstr;
+ // If nonzero, distance from the text segment to the read-only segment.
+ uint64_t rosegment_gap;
// The special section index for small common symbols; SHN_UNDEF
// if none.
elfcpp::Elf_Half small_common_shndx;
this->processor_specific_flags_ = flags;
this->are_processor_specific_flags_set_ = true;
}
-
+
#ifdef HAVE_TARGET_32_LITTLE
// Virtual functions which may be overridden by the child class.
virtual Object*
section_offset_type offset, size_t len) const;
// This must be overridden by the child class if it has target-specific
- // attributes subsection in the attribute section.
+ // attributes subsection in the attribute section.
virtual int
do_attribute_arg_type(int) const
{ gold_unreachable(); }
section_size_type view_size,
unsigned char* reloc_view,
section_size_type reloc_view_size) = 0;
-
+
// Perform target-specific processing in a relocatable link. This is
// only used if we use the relocation strategy RELOC_SPECIAL.
// RELINFO points to a Relocation_info structure. SH_TYPE is the relocation
section_size_type /* view_size */,
unsigned char* /* preloc_out*/)
{ gold_unreachable(); }
-
+
// Return the number of entries in the GOT. This is only used for
// laying out the incremental link info sections. A target needs
// to implement this to support incremental linking.
// testfile.cc -- Dummy ELF objects for testing purposes.
-// Copyright 2006, 2007, 2008, 2009, 2011 Free Software Foundation, Inc.
+// Copyright 2006, 2007, 2008, 2009, 2011, 2012 Free Software Foundation, Inc.
// Written by Ian Lance Taylor <iant@google.com>.
// This file is part of gold.
0x08000000, // default_text_segment_address
0x1000, // abi_pagesize
0x1000, // common_pagesize
+ false, // isolate_execinstr
+ 0, // rosegment_gap
elfcpp::SHN_UNDEF, // small_common_shndx
elfcpp::SHN_UNDEF, // large_common_shndx
0, // small_common_section_flags
: Target_selector(0xffff, size, big_endian, NULL, NULL)
{ }
- Target*
+ virtual Target*
do_instantiate_target()
{
gold_unreachable();
return NULL;
}
- Target*
- do_recognize(int, int, int)
+ virtual Target*
+ do_recognize(Input_file*, off_t, int, int, int)
{
if (size == 32)
{
return NULL;
}
- Target*
+ virtual Target*
do_recognize_by_name(const char*)
{ return NULL; }
- void
+ virtual void
do_supported_names(std::vector<const char*>*)
{ }
};
#include "target-select.h"
#include "tls.h"
#include "freebsd.h"
+#include "nacl.h"
#include "gc.h"
#include "icf.h"
using namespace gold;
// A class to handle the PLT data.
+// This is an abstract base class that handles most of the linker details
+// but does not know the actual contents of PLT entries. The derived
+// classes below fill in those details.
template<int size>
class Output_data_plt_x86_64 : public Output_section_data
public:
typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, false> Reloc_section;
- Output_data_plt_x86_64(Layout* layout, Output_data_got<64, false>* got,
+ Output_data_plt_x86_64(Layout* layout, uint64_t addralign,
+ Output_data_got<64, false>* got,
Output_data_space* got_plt,
Output_data_space* got_irelative)
- : Output_section_data(16), layout_(layout), tlsdesc_rel_(NULL),
+ : Output_section_data(addralign), layout_(layout), tlsdesc_rel_(NULL),
irelative_rel_(NULL), got_(got), got_plt_(got_plt),
got_irelative_(got_irelative), count_(0), irelative_count_(0),
tlsdesc_got_offset_(-1U), free_list_()
{ this->init(layout); }
- Output_data_plt_x86_64(Layout* layout, Output_data_got<64, false>* got,
+ Output_data_plt_x86_64(Layout* layout, uint64_t plt_entry_size,
+ Output_data_got<64, false>* got,
Output_data_space* got_plt,
Output_data_space* got_irelative,
unsigned int plt_count)
- : Output_section_data((plt_count + 1) * plt_entry_size, 16, false),
+ : Output_section_data((plt_count + 1) * plt_entry_size,
+ plt_entry_size, false),
layout_(layout), tlsdesc_rel_(NULL), irelative_rel_(NULL), got_(got),
got_plt_(got_plt), got_irelative_(got_irelative), count_(plt_count),
irelative_count_(0), tlsdesc_got_offset_(-1U), free_list_()
// Return the offset of the reserved TLSDESC_PLT entry.
unsigned int
get_tlsdesc_plt_offset() const
- { return (this->count_ + this->irelative_count_ + 1) * plt_entry_size; }
+ {
+ return ((this->count_ + this->irelative_count_ + 1)
+ * this->get_plt_entry_size());
+ }
// Return the .rela.plt section data.
Reloc_section*
{ return this->count_ + this->irelative_count_; }
// Return the offset of the first non-reserved PLT entry.
- static unsigned int
+ unsigned int
first_plt_entry_offset()
- { return plt_entry_size; }
+ { return this->get_plt_entry_size(); }
// Return the size of a PLT entry.
- static unsigned int
- get_plt_entry_size()
- { return plt_entry_size; }
+ unsigned int
+ get_plt_entry_size() const
+ { return this->do_get_plt_entry_size(); }
// Reserve a slot in the PLT for an existing symbol in an incremental update.
void
reserve_slot(unsigned int plt_index)
{
- this->free_list_.remove((plt_index + 1) * plt_entry_size,
- (plt_index + 2) * plt_entry_size);
+ this->free_list_.remove((plt_index + 1) * this->get_plt_entry_size(),
+ (plt_index + 2) * this->get_plt_entry_size());
}
// Return the PLT address to use for a global symbol.
uint64_t
address_for_local(const Relobj*, unsigned int symndx);
+ // Add .eh_frame information for the PLT.
+ void
+ add_eh_frame(Layout* layout)
+ { this->do_add_eh_frame(layout); }
+
protected:
+ // Fill in the first PLT entry.
+ void
+ fill_first_plt_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address)
+ { this->do_fill_first_plt_entry(pov, got_address, plt_address); }
+
+ // Fill in a normal PLT entry. Returns the offset into the entry that
+ // should be the initial GOT slot value.
+ unsigned int
+ fill_plt_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_index)
+ {
+ return this->do_fill_plt_entry(pov, got_address, plt_address,
+ got_offset, plt_offset, plt_index);
+ }
+
+ // Fill in the reserved TLSDESC PLT entry.
+ void
+ fill_tlsdesc_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_base,
+ unsigned int tlsdesc_got_offset,
+ unsigned int plt_offset)
+ {
+ this->do_fill_tlsdesc_entry(pov, got_address, plt_address, got_base,
+ tlsdesc_got_offset, plt_offset);
+ }
+
+ virtual unsigned int
+ do_get_plt_entry_size() const = 0;
+
+ virtual void
+ do_fill_first_plt_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_addr,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_addr)
+ = 0;
+
+ virtual unsigned int
+ do_fill_plt_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_index) = 0;
+
+ virtual void
+ do_fill_tlsdesc_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_base,
+ unsigned int tlsdesc_got_offset,
+ unsigned int plt_offset) = 0;
+
+ virtual void
+ do_add_eh_frame(Layout* layout) = 0;
+
void
do_adjust_output_section(Output_section* os);
do_print_to_mapfile(Mapfile* mapfile) const
{ mapfile->print_output_data(this, _("** PLT")); }
- private:
- // The size of an entry in the PLT.
- static const int plt_entry_size = 16;
-
- // The first entry in the PLT.
- // From the AMD64 ABI: "Unlike Intel386 ABI, this ABI uses the same
- // procedure linkage table for both programs and shared objects."
- static const unsigned char first_plt_entry[plt_entry_size];
-
- // Other entries in the PLT for an executable.
- static const unsigned char plt_entry[plt_entry_size];
-
- // The reserved TLSDESC entry in the PLT for an executable.
- static const unsigned char tlsdesc_plt_entry[plt_entry_size];
-
- // The .eh_frame unwind information for the PLT.
+ // The CIE of the .eh_frame unwind information for the PLT.
static const int plt_eh_frame_cie_size = 16;
- static const int plt_eh_frame_fde_size = 32;
static const unsigned char plt_eh_frame_cie[plt_eh_frame_cie_size];
- static const unsigned char plt_eh_frame_fde[plt_eh_frame_fde_size];
+ private:
// Set the final size.
void
set_final_data_size();
Free_list free_list_;
};
+template<int size>
+class Output_data_plt_x86_64_standard : public Output_data_plt_x86_64<size>
+{
+ public:
+ Output_data_plt_x86_64_standard(Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ : Output_data_plt_x86_64<size>(layout, plt_entry_size,
+ got, got_plt, got_irelative)
+ { }
+
+ Output_data_plt_x86_64_standard(Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative,
+ unsigned int plt_count)
+ : Output_data_plt_x86_64<size>(layout, plt_entry_size,
+ got, got_plt, got_irelative,
+ plt_count)
+ { }
+
+ protected:
+ virtual unsigned int
+ do_get_plt_entry_size() const
+ { return plt_entry_size; }
+
+ virtual void
+ do_add_eh_frame(Layout* layout)
+ {
+ layout->add_eh_frame_for_plt(this,
+ this->plt_eh_frame_cie,
+ this->plt_eh_frame_cie_size,
+ plt_eh_frame_fde,
+ plt_eh_frame_fde_size);
+ }
+
+ virtual void
+ do_fill_first_plt_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_addr,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_addr);
+
+ virtual unsigned int
+ do_fill_plt_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_index);
+
+ virtual void
+ do_fill_tlsdesc_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_base,
+ unsigned int tlsdesc_got_offset,
+ unsigned int plt_offset);
+
+ private:
+ // The size of an entry in the PLT.
+ static const int plt_entry_size = 16;
+
+ // The first entry in the PLT.
+ // From the AMD64 ABI: "Unlike Intel386 ABI, this ABI uses the same
+ // procedure linkage table for both programs and shared objects."
+ static const unsigned char first_plt_entry[plt_entry_size];
+
+ // Other entries in the PLT for an executable.
+ static const unsigned char plt_entry[plt_entry_size];
+
+ // The reserved TLSDESC entry in the PLT for an executable.
+ static const unsigned char tlsdesc_plt_entry[plt_entry_size];
+
+ // The .eh_frame unwind information for the PLT.
+ static const int plt_eh_frame_fde_size = 32;
+ static const unsigned char plt_eh_frame_fde[plt_eh_frame_fde_size];
+};
+
// The x86_64 target class.
// See the ABI at
// http://www.x86-64.org/documentation/abi.pdf
// uses only Elf64_Rela relocation entries with explicit addends."
typedef Output_data_reloc<elfcpp::SHT_RELA, true, size, false> Reloc_section;
- Target_x86_64()
- : Sized_target<size, false>(&x86_64_info),
+ Target_x86_64(const Target::Target_info* info = &x86_64_info)
+ : Sized_target<size, false>(info),
got_(NULL), plt_(NULL), got_plt_(NULL), got_irelative_(NULL),
got_tlsdesc_(NULL), global_offset_table_(NULL), rela_dyn_(NULL),
rela_irelative_(NULL), copy_relocs_(elfcpp::R_X86_64_COPY),
// Scan the relocations to look for symbol adjustments.
void
gc_process_relocs(Symbol_table* symtab,
- Layout* layout,
- Sized_relobj_file<size, false>* object,
- unsigned int data_shndx,
- unsigned int sh_type,
- const unsigned char* prelocs,
- size_t reloc_count,
- Output_section* output_section,
- bool needs_special_offset_handling,
- size_t local_symbol_count,
- const unsigned char* plocal_symbols);
+ Layout* layout,
+ Sized_relobj_file<size, false>* object,
+ unsigned int data_shndx,
+ unsigned int sh_type,
+ const unsigned char* prelocs,
+ size_t reloc_count,
+ Output_section* output_section,
+ bool needs_special_offset_handling,
+ size_t local_symbol_count,
+ const unsigned char* plocal_symbols);
// Scan the relocations to look for symbol adjustments.
void
// necessary dynamic relocations.
void
reserve_local_got_entry(unsigned int got_index,
- Sized_relobj<size, false>* obj,
+ Sized_relobj<size, false>* obj,
unsigned int r_sym,
unsigned int got_type);
return this->tlsdesc_reloc_info_.size() - 1;
}
+ Output_data_plt_x86_64<size>*
+ make_data_plt(Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ {
+ return this->do_make_data_plt(layout, got, got_plt, got_irelative);
+ }
+
+ Output_data_plt_x86_64<size>*
+ make_data_plt(Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative,
+ unsigned int plt_count)
+ {
+ return this->do_make_data_plt(layout, got, got_plt, got_irelative,
+ plt_count);
+ }
+
+ virtual Output_data_plt_x86_64<size>*
+ do_make_data_plt(Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ {
+ return new Output_data_plt_x86_64_standard<size>(layout, got, got_plt,
+ got_irelative);
+ }
+
+ virtual Output_data_plt_x86_64<size>*
+ do_make_data_plt(Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative,
+ unsigned int plt_count)
+ {
+ return new Output_data_plt_x86_64_standard<size>(layout, got, got_plt,
+ got_irelative,
+ plt_count);
+ }
+
private:
// The class which scans relocations.
class Scan
inline bool
local_reloc_may_be_function_pointer(Symbol_table* symtab, Layout* layout,
Target_x86_64* target,
- Sized_relobj_file<size, false>* object,
- unsigned int data_shndx,
- Output_section* output_section,
- const elfcpp::Rela<size, false>& reloc,
+ Sized_relobj_file<size, false>* object,
+ unsigned int data_shndx,
+ Output_section* output_section,
+ const elfcpp::Rela<size, false>& reloc,
unsigned int r_type,
- const elfcpp::Sym<size, false>& lsym);
+ const elfcpp::Sym<size, false>& lsym);
inline bool
global_reloc_may_be_function_pointer(Symbol_table* symtab, Layout* layout,
- Target_x86_64* target,
- Sized_relobj_file<size, false>* object,
- unsigned int data_shndx,
- Output_section* output_section,
- const elfcpp::Rela<size, false>& reloc,
+ Target_x86_64* target,
+ Sized_relobj_file<size, false>* object,
+ unsigned int data_shndx,
+ Output_section* output_section,
+ const elfcpp::Rela<size, false>& reloc,
unsigned int r_type,
- Symbol* gsym);
+ Symbol* gsym);
private:
static void
// Do a TLS relocation.
inline void
relocate_tls(const Relocate_info<size, false>*, Target_x86_64*,
- size_t relnum, const elfcpp::Rela<size, false>&,
+ size_t relnum, const elfcpp::Rela<size, false>&,
unsigned int r_type, const Sized_symbol<size>*,
const Symbol_value<size>*,
unsigned char*, typename elfcpp::Elf_types<size>::Elf_Addr,
// Add a potential copy relocation.
void
copy_reloc(Symbol_table* symtab, Layout* layout,
- Sized_relobj_file<size, false>* object,
+ Sized_relobj_file<size, false>* object,
unsigned int shndx, Output_section* output_section,
Symbol* sym, const elfcpp::Rela<size, false>& reloc)
{
0x400000, // default_text_segment_address
0x1000, // abi_pagesize (overridable by -z max-page-size)
0x1000, // common_pagesize (overridable by -z common-page-size)
+ false, // isolate_execinstr
+ 0, // rosegment_gap
elfcpp::SHN_UNDEF, // small_common_shndx
elfcpp::SHN_X86_64_LCOMMON, // large_common_shndx
0, // small_common_section_flags
0x400000, // default_text_segment_address
0x1000, // abi_pagesize (overridable by -z max-page-size)
0x1000, // common_pagesize (overridable by -z common-page-size)
+ false, // isolate_execinstr
+ 0, // rosegment_gap
elfcpp::SHN_UNDEF, // small_common_shndx
elfcpp::SHN_X86_64_LCOMMON, // large_common_shndx
0, // small_common_section_flags
layout->add_output_section_data(".rela.plt", elfcpp::SHT_RELA,
elfcpp::SHF_ALLOC, this->rel_,
ORDER_DYNAMIC_PLT_RELOCS, false);
-
- // Add unwind information if requested.
- if (parameters->options().ld_generated_unwind_info())
- layout->add_eh_frame_for_plt(this, plt_eh_frame_cie, plt_eh_frame_cie_size,
- plt_eh_frame_fde, plt_eh_frame_fde_size);
}
template<int size>
void
Output_data_plt_x86_64<size>::do_adjust_output_section(Output_section* os)
{
- os->set_entsize(plt_entry_size);
+ os->set_entsize(this->get_plt_entry_size());
}
// Add an entry to the PLT.
// Note that when setting the PLT offset for a non-IRELATIVE
// entry we skip the initial reserved PLT entry.
plt_index = *pcount + offset;
- plt_offset = plt_index * plt_entry_size;
+ plt_offset = plt_index * this->get_plt_entry_size();
++*pcount;
// FIXME: This is probably not correct for IRELATIVE relocs.
// For incremental updates, find an available slot.
- plt_offset = this->free_list_.allocate(plt_entry_size, plt_entry_size, 0);
+ plt_offset = this->free_list_.allocate(this->get_plt_entry_size(),
+ this->get_plt_entry_size(), 0);
if (plt_offset == -1)
gold_fallback(_("out of patch space (PLT);"
" relink with --incremental-full"));
// The GOT and PLT entries have a 1-1 correspondance, so the GOT offset
// can be calculated from the PLT index, adjusting for the three
// reserved entries at the beginning of the GOT.
- plt_index = plt_offset / plt_entry_size - 1;
+ plt_index = plt_offset / this->get_plt_entry_size() - 1;
got_offset = (plt_index - offset + reserved) * 8;
}
Sized_relobj_file<size, false>* relobj,
unsigned int local_sym_index)
{
- unsigned int plt_offset = this->irelative_count_ * plt_entry_size;
+ unsigned int plt_offset = this->irelative_count_ * this->get_plt_entry_size();
++this->irelative_count_;
section_offset_type got_offset = this->got_irelative_->current_data_size();
uint64_t offset = 0;
if (gsym->type() == elfcpp::STT_GNU_IFUNC
&& gsym->can_use_relative_reloc(false))
- offset = (this->count_ + 1) * plt_entry_size;
+ offset = (this->count_ + 1) * this->get_plt_entry_size();
return this->address() + offset;
}
uint64_t
Output_data_plt_x86_64<size>::address_for_local(const Relobj*, unsigned int)
{
- return this->address() + (this->count_ + 1) * plt_entry_size;
+ return this->address() + (this->count_ + 1) * this->get_plt_entry_size();
}
// Set the final size.
unsigned int count = this->count_ + this->irelative_count_;
if (this->has_tlsdesc_entry())
++count;
- this->set_data_size((count + 1) * plt_entry_size);
+ this->set_data_size((count + 1) * this->get_plt_entry_size());
}
// The first entry in the PLT for an executable.
template<int size>
const unsigned char
-Output_data_plt_x86_64<size>::first_plt_entry[plt_entry_size] =
+Output_data_plt_x86_64_standard<size>::first_plt_entry[plt_entry_size] =
{
// From AMD64 ABI Draft 0.98, page 76
0xff, 0x35, // pushq contents of memory address
0x90, 0x90, 0x90, 0x90 // noop (x4)
};
+template<int size>
+void
+Output_data_plt_x86_64_standard<size>::do_fill_first_plt_entry(
+ unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address)
+{
+ memcpy(pov, first_plt_entry, plt_entry_size);
+ // We do a jmp relative to the PC at the end of this instruction.
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
+ (got_address + 8
+ - (plt_address + 6)));
+ elfcpp::Swap<32, false>::writeval(pov + 8,
+ (got_address + 16
+ - (plt_address + 12)));
+}
+
// Subsequent entries in the PLT for an executable.
template<int size>
const unsigned char
-Output_data_plt_x86_64<size>::plt_entry[plt_entry_size] =
+Output_data_plt_x86_64_standard<size>::plt_entry[plt_entry_size] =
{
// From AMD64 ABI Draft 0.98, page 76
0xff, 0x25, // jmpq indirect
0, 0, 0, 0 // replaced with offset to start of .plt
};
+template<int size>
+unsigned int
+Output_data_plt_x86_64_standard<size>::do_fill_plt_entry(
+ unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_index)
+{
+ memcpy(pov, plt_entry, plt_entry_size);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
+ (got_address + got_offset
+ - (plt_address + plt_offset
+ + 6)));
+
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 7, plt_index);
+ elfcpp::Swap<32, false>::writeval(pov + 12,
+ - (plt_offset + plt_entry_size));
+
+ return 6;
+}
+
// The reserved TLSDESC entry in the PLT for an executable.
template<int size>
const unsigned char
-Output_data_plt_x86_64<size>::tlsdesc_plt_entry[plt_entry_size] =
+Output_data_plt_x86_64_standard<size>::tlsdesc_plt_entry[plt_entry_size] =
{
// From Alexandre Oliva, "Thread-Local Storage Descriptors for IA32
// and AMD64/EM64T", Version 0.9.4 (2005-10-10).
0x40, 0
};
+template<int size>
+void
+Output_data_plt_x86_64_standard<size>::do_fill_tlsdesc_entry(
+ unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_base,
+ unsigned int tlsdesc_got_offset,
+ unsigned int plt_offset)
+{
+ memcpy(pov, tlsdesc_plt_entry, plt_entry_size);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
+ (got_address + 8
+ - (plt_address + plt_offset
+ + 6)));
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 8,
+ (got_base
+ + tlsdesc_got_offset
+ - (plt_address + plt_offset
+ + 12)));
+}
+
// The .eh_frame unwind information for the PLT.
template<int size>
-const unsigned char
+const unsigned char
Output_data_plt_x86_64<size>::plt_eh_frame_cie[plt_eh_frame_cie_size] =
{
1, // CIE version.
template<int size>
const unsigned char
-Output_data_plt_x86_64<size>::plt_eh_frame_fde[plt_eh_frame_fde_size] =
+Output_data_plt_x86_64_standard<size>::plt_eh_frame_fde[plt_eh_frame_fde_size] =
{
0, 0, 0, 0, // Replaced with offset to .plt.
0, 0, 0, 0, // Replaced with size of .plt.
typename elfcpp::Elf_types<size>::Elf_Addr got_address
= this->got_plt_->address();
- memcpy(pov, first_plt_entry, plt_entry_size);
- // We do a jmp relative to the PC at the end of this instruction.
- elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
- (got_address + 8
- - (plt_address + 6)));
- elfcpp::Swap<32, false>::writeval(pov + 8,
- (got_address + 16
- - (plt_address + 12)));
- pov += plt_entry_size;
+ this->fill_first_plt_entry(pov, got_address, plt_address);
+ pov += this->get_plt_entry_size();
unsigned char* got_pov = got_view;
memset(got_pov, 0, 16);
got_pov += 16;
- unsigned int plt_offset = plt_entry_size;
+ unsigned int plt_offset = this->get_plt_entry_size();
unsigned int got_offset = 24;
const unsigned int count = this->count_ + this->irelative_count_;
for (unsigned int plt_index = 0;
plt_index < count;
++plt_index,
- pov += plt_entry_size,
+ pov += this->get_plt_entry_size(),
got_pov += 8,
- plt_offset += plt_entry_size,
+ plt_offset += this->get_plt_entry_size(),
got_offset += 8)
{
// Set and adjust the PLT entry itself.
- memcpy(pov, plt_entry, plt_entry_size);
- elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
- (got_address + got_offset
- - (plt_address + plt_offset
- + 6)));
-
- elfcpp::Swap_unaligned<32, false>::writeval(pov + 7, plt_index);
- elfcpp::Swap<32, false>::writeval(pov + 12,
- - (plt_offset + plt_entry_size));
+ unsigned int lazy_offset = this->fill_plt_entry(pov,
+ got_address, plt_address,
+ got_offset, plt_offset,
+ plt_index);
// Set the entry in the GOT.
- elfcpp::Swap<64, false>::writeval(got_pov, plt_address + plt_offset + 6);
+ elfcpp::Swap<64, false>::writeval(got_pov,
+ plt_address + plt_offset + lazy_offset);
}
if (this->has_tlsdesc_entry())
{
// Set and adjust the reserved TLSDESC PLT entry.
unsigned int tlsdesc_got_offset = this->get_tlsdesc_got_offset();
- memcpy(pov, tlsdesc_plt_entry, plt_entry_size);
- elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
- (got_address + 8
- - (plt_address + plt_offset
- + 6)));
- elfcpp::Swap_unaligned<32, false>::writeval(pov + 8,
- (got_base
- + tlsdesc_got_offset
- - (plt_address + plt_offset
- + 12)));
- pov += plt_entry_size;
+ this->fill_tlsdesc_entry(pov, got_address, plt_address, got_base,
+ tlsdesc_got_offset, plt_offset);
+ pov += this->get_plt_entry_size();
}
gold_assert(static_cast<section_size_type>(pov - oview) == oview_size);
// Create the GOT sections first.
this->got_section(symtab, layout);
- this->plt_ = new Output_data_plt_x86_64<size>(layout, this->got_,
- this->got_plt_,
- this->got_irelative_);
+ this->plt_ = this->make_data_plt(layout, this->got_, this->got_plt_,
+ this->got_irelative_);
+
+ // Add unwind information if requested.
+ if (parameters->options().ld_generated_unwind_info())
+ this->plt_->add_eh_frame(layout);
+
layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
(elfcpp::SHF_ALLOC
| elfcpp::SHF_EXECINSTR),
unsigned int
Target_x86_64<size>::first_plt_entry_offset() const
{
- return Output_data_plt_x86_64<size>::first_plt_entry_offset();
+ return this->plt_->first_plt_entry_offset();
}
// Return the size of each PLT entry.
unsigned int
Target_x86_64<size>::plt_entry_size() const
{
- return Output_data_plt_x86_64<size>::get_plt_entry_size();
+ return this->plt_->get_plt_entry_size();
}
// Create the GOT and PLT sections for an incremental update.
ORDER_NON_RELRO_FIRST, false);
// Create the PLT section.
- this->plt_ = new Output_data_plt_x86_64<size>(layout, this->got_,
- this->got_plt_,
- this->got_irelative_,
- plt_count);
+ this->plt_ = this->make_data_plt(layout, this->got_,
+ this->got_plt_,
+ this->got_irelative_,
+ plt_count);
+
+ // Add unwind information if requested.
+ if (parameters->options().ld_generated_unwind_info())
+ this->plt_->add_eh_frame(layout);
+
layout->add_output_section_data(".plt", elfcpp::SHT_PROGBITS,
elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR,
this->plt_, ORDER_PLT, false);
template<int size>
void
Target_x86_64<size>::reserve_tlsdesc_entries(Symbol_table* symtab,
- Layout* layout)
+ Layout* layout)
{
if (this->plt_ == NULL)
this->make_plt_section(symtab, layout);
Output_data_got<64, false>* got = this->got_section(symtab, layout);
unsigned int got_offset = got->add_constant(0);
rela_dyn->add_local(object, 0, elfcpp::R_X86_64_DTPMOD64, got,
- got_offset, 0);
+ got_offset, 0);
got->add_constant(0);
this->got_mod_index_offset_ = got_offset;
}
// section. But we can still wind up issuing more than one
// error per object file.
if (this->issued_non_pic_error_)
- return;
+ return;
gold_assert(parameters->options().output_is_position_independent());
object->error(_("requires unsupported dynamic reloc %u; "
- "recompile with -fPIC"),
+ "recompile with -fPIC"),
r_type);
this->issued_non_pic_error_ = true;
return;
int flags = Scan::get_reference_flags(r_type);
if (flags & Symbol::TLS_REF)
gold_error(_("%s: unsupported TLS reloc %u for IFUNC symbol"),
- object->name().c_str(), r_type);
+ object->name().c_str(), r_type);
return flags != 0;
}
// R_X86_64_RELATIVE relocation so the dynamic loader can
// relocate it easily.
if (parameters->options().output_is_position_independent())
- {
- unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
- Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
rela_dyn->add_local_relative(object, r_sym,
elfcpp::R_X86_64_RELATIVE,
output_section, data_shndx,
reloc.get_r_offset(),
reloc.get_r_addend(), is_ifunc);
- }
+ }
break;
case elfcpp::R_X86_64_32:
// location. We can't use an R_X86_64_RELATIVE relocation
// because that is always a 64-bit relocation.
if (parameters->options().output_is_position_independent())
- {
+ {
// Use R_X86_64_RELATIVE relocation for R_X86_64_32 under x32.
if (size == 32 && r_type == elfcpp::R_X86_64_32)
{
break;
}
- this->check_non_pic(object, r_type, NULL);
+ this->check_non_pic(object, r_type, NULL);
- Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
- if (lsym.get_st_type() != elfcpp::STT_SECTION)
+ if (lsym.get_st_type() != elfcpp::STT_SECTION)
rela_dyn->add_local(object, r_sym, r_type, output_section,
data_shndx, reloc.get_r_offset(),
reloc.get_r_addend());
- else
- {
- gold_assert(lsym.get_st_value() == 0);
+ else
+ {
+ gold_assert(lsym.get_st_value() == 0);
unsigned int shndx = lsym.get_st_shndx();
bool is_ordinary;
shndx = object->adjust_sym_shndx(r_sym, shndx,
r_type, output_section,
data_shndx, reloc.get_r_offset(),
reloc.get_r_addend());
- }
- }
+ }
+ }
break;
case elfcpp::R_X86_64_PC64:
case elfcpp::R_X86_64_GOTPCREL:
case elfcpp::R_X86_64_GOTPLT64:
{
- // The symbol requires a GOT entry.
- Output_data_got<64, false>* got = target->got_section(symtab, layout);
- unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ // The symbol requires a GOT entry.
+ Output_data_got<64, false>* got = target->got_section(symtab, layout);
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
// For a STT_GNU_IFUNC symbol we want the PLT offset. That
// lets function pointers compare correctly with shared
is_new = got->add_local_plt(object, r_sym, GOT_TYPE_STANDARD);
else
is_new = got->add_local(object, r_sym, GOT_TYPE_STANDARD);
- if (is_new)
- {
- // If we are generating a shared object, we need to add a
- // dynamic relocation for this symbol's GOT entry.
- if (parameters->options().output_is_position_independent())
- {
- Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ if (is_new)
+ {
+ // If we are generating a shared object, we need to add a
+ // dynamic relocation for this symbol's GOT entry.
+ if (parameters->options().output_is_position_independent())
+ {
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
// R_X86_64_RELATIVE assumes a 64-bit relocation.
if (r_type != elfcpp::R_X86_64_GOT32)
{
elfcpp::R_X86_64_RELATIVE,
got, got_offset, 0, is_ifunc);
}
- else
- {
- this->check_non_pic(object, r_type, NULL);
-
- gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION);
- rela_dyn->add_local(
- object, r_sym, r_type, got,
- object->local_got_offset(r_sym, GOT_TYPE_STANDARD), 0);
- }
- }
- }
- // For GOTPLT64, we'd normally want a PLT section, but since
- // we know this is a local symbol, no PLT is needed.
+ else
+ {
+ this->check_non_pic(object, r_type, NULL);
+
+ gold_assert(lsym.get_st_type() != elfcpp::STT_SECTION);
+ rela_dyn->add_local(
+ object, r_sym, r_type, got,
+ object->local_got_offset(r_sym, GOT_TYPE_STANDARD), 0);
+ }
+ }
+ }
+ // For GOTPLT64, we'd normally want a PLT section, but since
+ // we know this is a local symbol, no PLT is needed.
}
break;
{
bool output_is_shared = parameters->options().shared();
const tls::Tls_optimization optimized_type
- = Target_x86_64<size>::optimize_tls_reloc(!output_is_shared,
+ = Target_x86_64<size>::optimize_tls_reloc(!output_is_shared,
r_type);
switch (r_type)
{
- case elfcpp::R_X86_64_TLSGD: // General-dynamic
- if (optimized_type == tls::TLSOPT_NONE)
- {
- // Create a pair of GOT entries for the module index and
- // dtv-relative offset.
- Output_data_got<64, false>* got
- = target->got_section(symtab, layout);
- unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ case elfcpp::R_X86_64_TLSGD: // General-dynamic
+ if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Create a pair of GOT entries for the module index and
+ // dtv-relative offset.
+ Output_data_got<64, false>* got
+ = target->got_section(symtab, layout);
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
unsigned int shndx = lsym.get_st_shndx();
bool is_ordinary;
shndx = object->adjust_sym_shndx(r_sym, shndx, &is_ordinary);
if (!is_ordinary)
object->error(_("local symbol %u has bad shndx %u"),
r_sym, shndx);
- else
+ else
got->add_local_pair_with_rel(object, r_sym,
shndx,
GOT_TYPE_TLS_PAIR,
target->rela_dyn_section(layout),
elfcpp::R_X86_64_DTPMOD64, 0);
- }
- else if (optimized_type != tls::TLSOPT_TO_LE)
+ }
+ else if (optimized_type != tls::TLSOPT_TO_LE)
unsupported_reloc_local(object, r_type);
- break;
+ break;
- case elfcpp::R_X86_64_GOTPC32_TLSDESC:
- target->define_tls_base_symbol(symtab, layout);
+ case elfcpp::R_X86_64_GOTPC32_TLSDESC:
+ target->define_tls_base_symbol(symtab, layout);
if (optimized_type == tls::TLSOPT_NONE)
{
- // Create reserved PLT and GOT entries for the resolver.
- target->reserve_tlsdesc_entries(symtab, layout);
-
- // Generate a double GOT entry with an
- // R_X86_64_TLSDESC reloc. The R_X86_64_TLSDESC reloc
- // is resolved lazily, so the GOT entry needs to be in
- // an area in .got.plt, not .got. Call got_section to
- // make sure the section has been created.
+ // Create reserved PLT and GOT entries for the resolver.
+ target->reserve_tlsdesc_entries(symtab, layout);
+
+ // Generate a double GOT entry with an
+ // R_X86_64_TLSDESC reloc. The R_X86_64_TLSDESC reloc
+ // is resolved lazily, so the GOT entry needs to be in
+ // an area in .got.plt, not .got. Call got_section to
+ // make sure the section has been created.
target->got_section(symtab, layout);
- Output_data_got<64, false>* got = target->got_tlsdesc_section();
- unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ Output_data_got<64, false>* got = target->got_tlsdesc_section();
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
if (!object->local_has_got_offset(r_sym, GOT_TYPE_TLS_DESC))
{
unsigned int got_offset = got->add_constant(0);
unsupported_reloc_local(object, r_type);
break;
- case elfcpp::R_X86_64_TLSDESC_CALL:
+ case elfcpp::R_X86_64_TLSDESC_CALL:
break;
- case elfcpp::R_X86_64_TLSLD: // Local-dynamic
+ case elfcpp::R_X86_64_TLSLD: // Local-dynamic
if (optimized_type == tls::TLSOPT_NONE)
{
- // Create a GOT entry for the module index.
- target->got_mod_index_entry(symtab, layout, object);
+ // Create a GOT entry for the module index.
+ target->got_mod_index_entry(symtab, layout, object);
}
else if (optimized_type != tls::TLSOPT_TO_LE)
unsupported_reloc_local(object, r_type);
break;
- case elfcpp::R_X86_64_DTPOFF32:
- case elfcpp::R_X86_64_DTPOFF64:
+ case elfcpp::R_X86_64_DTPOFF32:
+ case elfcpp::R_X86_64_DTPOFF64:
break;
- case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec
+ case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec
layout->set_has_static_tls();
- if (optimized_type == tls::TLSOPT_NONE)
- {
- // Create a GOT entry for the tp-relative offset.
- Output_data_got<64, false>* got
- = target->got_section(symtab, layout);
- unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
- got->add_local_with_rel(object, r_sym, GOT_TYPE_TLS_OFFSET,
+ if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Create a GOT entry for the tp-relative offset.
+ Output_data_got<64, false>* got
+ = target->got_section(symtab, layout);
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(reloc.get_r_info());
+ got->add_local_with_rel(object, r_sym, GOT_TYPE_TLS_OFFSET,
target->rela_dyn_section(layout),
elfcpp::R_X86_64_TPOFF64);
- }
- else if (optimized_type != tls::TLSOPT_TO_LE)
- unsupported_reloc_local(object, r_type);
- break;
+ }
+ else if (optimized_type != tls::TLSOPT_TO_LE)
+ unsupported_reloc_local(object, r_type);
+ break;
- case elfcpp::R_X86_64_TPOFF32: // Local-exec
+ case elfcpp::R_X86_64_TPOFF32: // Local-exec
layout->set_has_static_tls();
- if (output_is_shared)
- unsupported_reloc_local(object, r_type);
+ if (output_is_shared)
+ unsupported_reloc_local(object, r_type);
break;
- default:
- gold_unreachable();
+ default:
+ gold_unreachable();
}
}
break;
case elfcpp::R_X86_64_GOTPCREL:
case elfcpp::R_X86_64_GOTPLT64:
{
- return true;
+ return true;
}
}
return false;
// not possible to distinguish pointer taken versus a call by looking at
// the relocation types.
return (parameters->options().shared()
- || possible_function_pointer_reloc(r_type));
+ || possible_function_pointer_reloc(r_type));
}
// For safe ICF, scan a relocation for a global symbol to check if it
// When building a shared library, do not fold symbols whose visibility
// is hidden, internal or protected.
return ((parameters->options().shared()
- && (gsym->visibility() == elfcpp::STV_INTERNAL
+ && (gsym->visibility() == elfcpp::STV_INTERNAL
|| gsym->visibility() == elfcpp::STV_PROTECTED
|| gsym->visibility() == elfcpp::STV_HIDDEN))
- || possible_function_pointer_reloc(r_type));
+ || possible_function_pointer_reloc(r_type));
}
// Scan a relocation for a global symbol.
template<int size>
inline void
Target_x86_64<size>::Scan::global(Symbol_table* symtab,
- Layout* layout,
- Target_x86_64<size>* target,
- Sized_relobj_file<size, false>* object,
- unsigned int data_shndx,
- Output_section* output_section,
- const elfcpp::Rela<size, false>& reloc,
- unsigned int r_type,
- Symbol* gsym)
+ Layout* layout,
+ Target_x86_64<size>* target,
+ Sized_relobj_file<size, false>* object,
+ unsigned int data_shndx,
+ Output_section* output_section,
+ const elfcpp::Rela<size, false>& reloc,
+ unsigned int r_type,
+ Symbol* gsym)
{
// A STT_GNU_IFUNC symbol may require a PLT entry.
if (gsym->type() == elfcpp::STT_GNU_IFUNC
case elfcpp::R_X86_64_16:
case elfcpp::R_X86_64_8:
{
- // Make a PLT entry if necessary.
- if (gsym->needs_plt_entry())
- {
- target->make_plt_entry(symtab, layout, gsym);
- // Since this is not a PC-relative relocation, we may be
- // taking the address of a function. In that case we need to
- // set the entry in the dynamic symbol table to the address of
- // the PLT entry.
- if (gsym->is_from_dynobj() && !parameters->options().shared())
- gsym->set_needs_dynsym_value();
- }
- // Make a dynamic relocation if necessary.
- if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
- {
- if (gsym->may_need_copy_reloc())
- {
- target->copy_reloc(symtab, layout, object,
- data_shndx, output_section, gsym, reloc);
- }
+ // Make a PLT entry if necessary.
+ if (gsym->needs_plt_entry())
+ {
+ target->make_plt_entry(symtab, layout, gsym);
+ // Since this is not a PC-relative relocation, we may be
+ // taking the address of a function. In that case we need to
+ // set the entry in the dynamic symbol table to the address of
+ // the PLT entry.
+ if (gsym->is_from_dynobj() && !parameters->options().shared())
+ gsym->set_needs_dynsym_value();
+ }
+ // Make a dynamic relocation if necessary.
+ if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
+ {
+ if (gsym->may_need_copy_reloc())
+ {
+ target->copy_reloc(symtab, layout, object,
+ data_shndx, output_section, gsym, reloc);
+ }
else if (((size == 64 && r_type == elfcpp::R_X86_64_64)
|| (size == 32 && r_type == elfcpp::R_X86_64_32))
&& gsym->type() == elfcpp::STT_GNU_IFUNC
reloc.get_r_offset(),
reloc.get_r_addend());
}
- else if (r_type == elfcpp::R_X86_64_64
- && gsym->can_use_relative_reloc(false))
- {
- Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ else if (r_type == elfcpp::R_X86_64_64
+ && gsym->can_use_relative_reloc(false))
+ {
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
rela_dyn->add_global_relative(gsym, elfcpp::R_X86_64_RELATIVE,
output_section, object,
data_shndx,
reloc.get_r_offset(),
reloc.get_r_addend(), false);
- }
- else
- {
- this->check_non_pic(object, r_type, gsym);
- Reloc_section* rela_dyn = target->rela_dyn_section(layout);
- rela_dyn->add_global(gsym, r_type, output_section, object,
- data_shndx, reloc.get_r_offset(),
- reloc.get_r_addend());
- }
- }
+ }
+ else
+ {
+ this->check_non_pic(object, r_type, gsym);
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ rela_dyn->add_global(gsym, r_type, output_section, object,
+ data_shndx, reloc.get_r_offset(),
+ reloc.get_r_addend());
+ }
+ }
}
break;
case elfcpp::R_X86_64_PC16:
case elfcpp::R_X86_64_PC8:
{
- // Make a PLT entry if necessary.
- if (gsym->needs_plt_entry())
- target->make_plt_entry(symtab, layout, gsym);
- // Make a dynamic relocation if necessary.
- if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
- {
- if (gsym->may_need_copy_reloc())
- {
- target->copy_reloc(symtab, layout, object,
- data_shndx, output_section, gsym, reloc);
- }
- else
- {
- this->check_non_pic(object, r_type, gsym);
- Reloc_section* rela_dyn = target->rela_dyn_section(layout);
- rela_dyn->add_global(gsym, r_type, output_section, object,
- data_shndx, reloc.get_r_offset(),
- reloc.get_r_addend());
- }
- }
+ // Make a PLT entry if necessary.
+ if (gsym->needs_plt_entry())
+ target->make_plt_entry(symtab, layout, gsym);
+ // Make a dynamic relocation if necessary.
+ if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)))
+ {
+ if (gsym->may_need_copy_reloc())
+ {
+ target->copy_reloc(symtab, layout, object,
+ data_shndx, output_section, gsym, reloc);
+ }
+ else
+ {
+ this->check_non_pic(object, r_type, gsym);
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ rela_dyn->add_global(gsym, r_type, output_section, object,
+ data_shndx, reloc.get_r_offset(),
+ reloc.get_r_addend());
+ }
+ }
}
break;
case elfcpp::R_X86_64_GOTPCREL:
case elfcpp::R_X86_64_GOTPLT64:
{
- // The symbol requires a GOT entry.
- Output_data_got<64, false>* got = target->got_section(symtab, layout);
- if (gsym->final_value_is_known())
+ // The symbol requires a GOT entry.
+ Output_data_got<64, false>* got = target->got_section(symtab, layout);
+ if (gsym->final_value_is_known())
{
// For a STT_GNU_IFUNC symbol we want the PLT address.
if (gsym->type() == elfcpp::STT_GNU_IFUNC)
else
got->add_global(gsym, GOT_TYPE_STANDARD);
}
- else
- {
- // If this symbol is not fully resolved, we need to add a
- // dynamic relocation for it.
- Reloc_section* rela_dyn = target->rela_dyn_section(layout);
+ else
+ {
+ // If this symbol is not fully resolved, we need to add a
+ // dynamic relocation for it.
+ Reloc_section* rela_dyn = target->rela_dyn_section(layout);
// Use a GLOB_DAT rather than a RELATIVE reloc if:
//
&& parameters->options().shared())
|| (gsym->type() == elfcpp::STT_GNU_IFUNC
&& parameters->options().output_is_position_independent()))
- got->add_global_with_rel(gsym, GOT_TYPE_STANDARD, rela_dyn,
+ got->add_global_with_rel(gsym, GOT_TYPE_STANDARD, rela_dyn,
elfcpp::R_X86_64_GLOB_DAT);
- else
- {
+ else
+ {
// For a STT_GNU_IFUNC symbol we want to write the PLT
// offset into the GOT, so that function pointer
// comparisons work correctly.
&& !parameters->options().shared())
gsym->set_needs_dynsym_value();
}
- if (is_new)
+ if (is_new)
{
unsigned int got_off = gsym->got_offset(GOT_TYPE_STANDARD);
rela_dyn->add_global_relative(gsym,
elfcpp::R_X86_64_RELATIVE,
got, got_off, 0, false);
}
- }
- }
- // For GOTPLT64, we also need a PLT entry (but only if the
- // symbol is not fully resolved).
- if (r_type == elfcpp::R_X86_64_GOTPLT64
- && !gsym->final_value_is_known())
- target->make_plt_entry(symtab, layout, gsym);
+ }
+ }
+ // For GOTPLT64, we also need a PLT entry (but only if the
+ // symbol is not fully resolved).
+ if (r_type == elfcpp::R_X86_64_GOTPLT64
+ && !gsym->final_value_is_known())
+ target->make_plt_entry(symtab, layout, gsym);
}
break;
// if the symbol is defined in the output file and is protected
// or hidden.
if (gsym->is_defined()
- && !gsym->is_from_dynobj()
- && !gsym->is_preemptible())
+ && !gsym->is_from_dynobj()
+ && !gsym->is_preemptible())
break;
target->make_plt_entry(symtab, layout, gsym);
break;
{
const bool is_final = gsym->final_value_is_known();
const tls::Tls_optimization optimized_type
- = Target_x86_64<size>::optimize_tls_reloc(is_final, r_type);
+ = Target_x86_64<size>::optimize_tls_reloc(is_final, r_type);
switch (r_type)
{
- case elfcpp::R_X86_64_TLSGD: // General-dynamic
+ case elfcpp::R_X86_64_TLSGD: // General-dynamic
if (optimized_type == tls::TLSOPT_NONE)
{
- // Create a pair of GOT entries for the module index and
- // dtv-relative offset.
- Output_data_got<64, false>* got
- = target->got_section(symtab, layout);
- got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_PAIR,
+ // Create a pair of GOT entries for the module index and
+ // dtv-relative offset.
+ Output_data_got<64, false>* got
+ = target->got_section(symtab, layout);
+ got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_PAIR,
target->rela_dyn_section(layout),
elfcpp::R_X86_64_DTPMOD64,
elfcpp::R_X86_64_DTPOFF64);
}
else if (optimized_type == tls::TLSOPT_TO_IE)
{
- // Create a GOT entry for the tp-relative offset.
- Output_data_got<64, false>* got
- = target->got_section(symtab, layout);
- got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
+ // Create a GOT entry for the tp-relative offset.
+ Output_data_got<64, false>* got
+ = target->got_section(symtab, layout);
+ got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
target->rela_dyn_section(layout),
elfcpp::R_X86_64_TPOFF64);
}
unsupported_reloc_global(object, r_type, gsym);
break;
- case elfcpp::R_X86_64_GOTPC32_TLSDESC:
- target->define_tls_base_symbol(symtab, layout);
+ case elfcpp::R_X86_64_GOTPC32_TLSDESC:
+ target->define_tls_base_symbol(symtab, layout);
if (optimized_type == tls::TLSOPT_NONE)
{
- // Create reserved PLT and GOT entries for the resolver.
- target->reserve_tlsdesc_entries(symtab, layout);
-
- // Create a double GOT entry with an R_X86_64_TLSDESC
- // reloc. The R_X86_64_TLSDESC reloc is resolved
- // lazily, so the GOT entry needs to be in an area in
- // .got.plt, not .got. Call got_section to make sure
- // the section has been created.
+ // Create reserved PLT and GOT entries for the resolver.
+ target->reserve_tlsdesc_entries(symtab, layout);
+
+ // Create a double GOT entry with an R_X86_64_TLSDESC
+ // reloc. The R_X86_64_TLSDESC reloc is resolved
+ // lazily, so the GOT entry needs to be in an area in
+ // .got.plt, not .got. Call got_section to make sure
+ // the section has been created.
target->got_section(symtab, layout);
- Output_data_got<64, false>* got = target->got_tlsdesc_section();
+ Output_data_got<64, false>* got = target->got_tlsdesc_section();
Reloc_section* rt = target->rela_tlsdesc_section(layout);
- got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_DESC, rt,
+ got->add_global_pair_with_rel(gsym, GOT_TYPE_TLS_DESC, rt,
elfcpp::R_X86_64_TLSDESC, 0);
}
else if (optimized_type == tls::TLSOPT_TO_IE)
{
- // Create a GOT entry for the tp-relative offset.
- Output_data_got<64, false>* got
- = target->got_section(symtab, layout);
- got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
+ // Create a GOT entry for the tp-relative offset.
+ Output_data_got<64, false>* got
+ = target->got_section(symtab, layout);
+ got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
target->rela_dyn_section(layout),
elfcpp::R_X86_64_TPOFF64);
}
unsupported_reloc_global(object, r_type, gsym);
break;
- case elfcpp::R_X86_64_TLSDESC_CALL:
+ case elfcpp::R_X86_64_TLSDESC_CALL:
break;
- case elfcpp::R_X86_64_TLSLD: // Local-dynamic
+ case elfcpp::R_X86_64_TLSLD: // Local-dynamic
if (optimized_type == tls::TLSOPT_NONE)
{
- // Create a GOT entry for the module index.
- target->got_mod_index_entry(symtab, layout, object);
+ // Create a GOT entry for the module index.
+ target->got_mod_index_entry(symtab, layout, object);
}
else if (optimized_type != tls::TLSOPT_TO_LE)
unsupported_reloc_global(object, r_type, gsym);
break;
- case elfcpp::R_X86_64_DTPOFF32:
- case elfcpp::R_X86_64_DTPOFF64:
+ case elfcpp::R_X86_64_DTPOFF32:
+ case elfcpp::R_X86_64_DTPOFF64:
break;
- case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec
+ case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec
layout->set_has_static_tls();
- if (optimized_type == tls::TLSOPT_NONE)
- {
- // Create a GOT entry for the tp-relative offset.
- Output_data_got<64, false>* got
- = target->got_section(symtab, layout);
- got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
+ if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Create a GOT entry for the tp-relative offset.
+ Output_data_got<64, false>* got
+ = target->got_section(symtab, layout);
+ got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET,
target->rela_dyn_section(layout),
elfcpp::R_X86_64_TPOFF64);
- }
- else if (optimized_type != tls::TLSOPT_TO_LE)
- unsupported_reloc_global(object, r_type, gsym);
- break;
+ }
+ else if (optimized_type != tls::TLSOPT_TO_LE)
+ unsupported_reloc_global(object, r_type, gsym);
+ break;
- case elfcpp::R_X86_64_TPOFF32: // Local-exec
+ case elfcpp::R_X86_64_TPOFF32: // Local-exec
layout->set_has_static_tls();
- if (parameters->options().shared())
- unsupported_reloc_local(object, r_type);
+ if (parameters->options().shared())
+ unsupported_reloc_local(object, r_type);
break;
- default:
- gold_unreachable();
+ default:
+ gold_unreachable();
}
}
break;
default:
gold_error(_("%s: unsupported reloc %u against global symbol %s"),
object->name().c_str(), r_type,
- gsym->demangled_name().c_str());
+ gsym->demangled_name().c_str());
break;
}
}
}
gold::gc_process_relocs<size, false, Target_x86_64<size>, elfcpp::SHT_RELA,
- typename Target_x86_64<size>::Scan,
+ typename Target_x86_64<size>::Scan,
typename Target_x86_64<size>::Relocatable_size_for_reloc>(
symtab,
layout,
needs_special_offset_handling,
local_symbol_count,
plocal_symbols);
-
+
}
// Scan relocations for a section.
: this->plt_->rela_plt());
layout->add_target_dynamic_tags(false, this->got_plt_, rel_plt,
this->rela_dyn_, true, false);
-
+
// Fill in some more dynamic tags.
Output_data_dynamic* const odyn = layout->dynamic_data();
if (odyn != NULL)
if (this->skip_call_tls_get_addr_)
{
if ((r_type != elfcpp::R_X86_64_PLT32
- && r_type != elfcpp::R_X86_64_PC32)
+ && r_type != elfcpp::R_X86_64_PC32)
|| gsym == NULL
|| strcmp(gsym->name(), "__tls_get_addr") != 0)
{
case elfcpp::R_X86_64_GOTPCREL:
case elfcpp::R_X86_64_GOTPCREL64:
if (gsym != NULL)
- {
- gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD));
- got_offset = gsym->got_offset(GOT_TYPE_STANDARD) - target->got_size();
- }
+ {
+ gold_assert(gsym->has_got_offset(GOT_TYPE_STANDARD));
+ got_offset = gsym->got_offset(GOT_TYPE_STANDARD) - target->got_size();
+ }
else
- {
- unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
- gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD));
- got_offset = (object->local_got_offset(r_sym, GOT_TYPE_STANDARD)
- - target->got_size());
- }
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
+ gold_assert(object->local_has_got_offset(r_sym, GOT_TYPE_STANDARD));
+ got_offset = (object->local_got_offset(r_sym, GOT_TYPE_STANDARD)
+ - target->got_size());
+ }
have_got_offset = true;
break;
case elfcpp::R_X86_64_PC64:
Relocate_functions<size, false>::pcrela64(view, object, psymval, addend,
- address);
+ address);
break;
case elfcpp::R_X86_64_32:
case elfcpp::R_X86_64_PLT32:
gold_assert(gsym == NULL
- || gsym->has_plt_offset()
+ || gsym->has_plt_offset()
|| gsym->final_value_is_known()
|| (gsym->is_defined()
&& !gsym->is_from_dynobj()
case elfcpp::R_X86_64_PLTOFF64:
{
- gold_assert(gsym);
- gold_assert(gsym->has_plt_offset()
- || gsym->final_value_is_known());
+ gold_assert(gsym);
+ gold_assert(gsym->has_plt_offset()
+ || gsym->final_value_is_known());
typename elfcpp::Elf_types<size>::Elf_Addr got_address;
got_address = target->got_section(NULL, NULL)->address();
Relocate_functions<size, false>::rela64(view, object, psymval,
case elfcpp::R_X86_64_GOTPC32:
{
- gold_assert(gsym);
+ gold_assert(gsym);
typename elfcpp::Elf_types<size>::Elf_Addr value;
value = target->got_plt_section()->address();
Relocate_functions<size, false>::pcrela32(view, value, addend, address);
case elfcpp::R_X86_64_GOTPC64:
{
- gold_assert(gsym);
+ gold_assert(gsym);
typename elfcpp::Elf_types<size>::Elf_Addr value;
value = target->got_plt_section()->address();
Relocate_functions<size, false>::pcrela64(view, value, addend, address);
case elfcpp::R_X86_64_GOTPCREL:
{
- gold_assert(have_got_offset);
- typename elfcpp::Elf_types<size>::Elf_Addr value;
- value = target->got_plt_section()->address() + got_offset;
- Relocate_functions<size, false>::pcrela32(view, value, addend, address);
+ gold_assert(have_got_offset);
+ typename elfcpp::Elf_types<size>::Elf_Addr value;
+ value = target->got_plt_section()->address() + got_offset;
+ Relocate_functions<size, false>::pcrela32(view, value, addend, address);
}
break;
case elfcpp::R_X86_64_GOTPCREL64:
{
- gold_assert(have_got_offset);
- typename elfcpp::Elf_types<size>::Elf_Addr value;
- value = target->got_plt_section()->address() + got_offset;
- Relocate_functions<size, false>::pcrela64(view, value, addend, address);
+ gold_assert(have_got_offset);
+ typename elfcpp::Elf_types<size>::Elf_Addr value;
+ value = target->got_plt_section()->address() + got_offset;
+ Relocate_functions<size, false>::pcrela64(view, value, addend, address);
}
break;
case elfcpp::R_X86_64_GOTTPOFF: // Initial-exec
case elfcpp::R_X86_64_TPOFF32: // Local-exec
this->relocate_tls(relinfo, target, relnum, rela, r_type, gsym, psymval,
- view, address, view_size);
+ view, address, view_size);
break;
case elfcpp::R_X86_64_SIZE32:
break;
}
else
- {
- unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE
- ? GOT_TYPE_TLS_OFFSET
- : GOT_TYPE_TLS_PAIR);
- unsigned int got_offset;
- if (gsym != NULL)
- {
- gold_assert(gsym->has_got_offset(got_type));
- got_offset = gsym->got_offset(got_type) - target->got_size();
- }
- else
- {
- unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
- gold_assert(object->local_has_got_offset(r_sym, got_type));
- got_offset = (object->local_got_offset(r_sym, got_type)
- - target->got_size());
- }
- if (optimized_type == tls::TLSOPT_TO_IE)
- {
- value = target->got_plt_section()->address() + got_offset;
- this->tls_gd_to_ie(relinfo, relnum, tls_segment, rela, r_type,
- value, view, address, view_size);
- break;
- }
- else if (optimized_type == tls::TLSOPT_NONE)
- {
- // Relocate the field with the offset of the pair of GOT
- // entries.
+ {
+ unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE
+ ? GOT_TYPE_TLS_OFFSET
+ : GOT_TYPE_TLS_PAIR);
+ unsigned int got_offset;
+ if (gsym != NULL)
+ {
+ gold_assert(gsym->has_got_offset(got_type));
+ got_offset = gsym->got_offset(got_type) - target->got_size();
+ }
+ else
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
+ gold_assert(object->local_has_got_offset(r_sym, got_type));
+ got_offset = (object->local_got_offset(r_sym, got_type)
+ - target->got_size());
+ }
+ if (optimized_type == tls::TLSOPT_TO_IE)
+ {
+ value = target->got_plt_section()->address() + got_offset;
+ this->tls_gd_to_ie(relinfo, relnum, tls_segment, rela, r_type,
+ value, view, address, view_size);
+ break;
+ }
+ else if (optimized_type == tls::TLSOPT_NONE)
+ {
+ // Relocate the field with the offset of the pair of GOT
+ // entries.
value = target->got_plt_section()->address() + got_offset;
- Relocate_functions<size, false>::pcrela32(view, value, addend,
+ Relocate_functions<size, false>::pcrela32(view, value, addend,
address);
- break;
- }
- }
+ break;
+ }
+ }
gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
_("unsupported reloc %u"), r_type);
break;
return;
}
this->tls_desc_gd_to_le(relinfo, relnum, tls_segment,
- rela, r_type, value, view,
- view_size);
+ rela, r_type, value, view,
+ view_size);
break;
}
else
- {
- unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE
- ? GOT_TYPE_TLS_OFFSET
- : GOT_TYPE_TLS_DESC);
- unsigned int got_offset = 0;
+ {
+ unsigned int got_type = (optimized_type == tls::TLSOPT_TO_IE
+ ? GOT_TYPE_TLS_OFFSET
+ : GOT_TYPE_TLS_DESC);
+ unsigned int got_offset = 0;
if (r_type == elfcpp::R_X86_64_GOTPC32_TLSDESC
&& optimized_type == tls::TLSOPT_NONE)
{
got_offset = (target->got_size()
+ target->got_plt_section()->data_size());
}
- if (gsym != NULL)
- {
- gold_assert(gsym->has_got_offset(got_type));
- got_offset += gsym->got_offset(got_type) - target->got_size();
- }
- else
- {
- unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
- gold_assert(object->local_has_got_offset(r_sym, got_type));
- got_offset += (object->local_got_offset(r_sym, got_type)
+ if (gsym != NULL)
+ {
+ gold_assert(gsym->has_got_offset(got_type));
+ got_offset += gsym->got_offset(got_type) - target->got_size();
+ }
+ else
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
+ gold_assert(object->local_has_got_offset(r_sym, got_type));
+ got_offset += (object->local_got_offset(r_sym, got_type)
- target->got_size());
- }
- if (optimized_type == tls::TLSOPT_TO_IE)
- {
+ }
+ if (optimized_type == tls::TLSOPT_TO_IE)
+ {
if (tls_segment == NULL)
{
gold_assert(parameters->errors()->error_count() > 0
|| issue_undefined_symbol_error(gsym));
return;
}
- value = target->got_plt_section()->address() + got_offset;
- this->tls_desc_gd_to_ie(relinfo, relnum, tls_segment,
- rela, r_type, value, view, address,
- view_size);
- break;
- }
- else if (optimized_type == tls::TLSOPT_NONE)
- {
- if (r_type == elfcpp::R_X86_64_GOTPC32_TLSDESC)
- {
- // Relocate the field with the offset of the pair of GOT
- // entries.
- value = target->got_plt_section()->address() + got_offset;
- Relocate_functions<size, false>::pcrela32(view, value, addend,
+ value = target->got_plt_section()->address() + got_offset;
+ this->tls_desc_gd_to_ie(relinfo, relnum, tls_segment,
+ rela, r_type, value, view, address,
+ view_size);
+ break;
+ }
+ else if (optimized_type == tls::TLSOPT_NONE)
+ {
+ if (r_type == elfcpp::R_X86_64_GOTPC32_TLSDESC)
+ {
+ // Relocate the field with the offset of the pair of GOT
+ // entries.
+ value = target->got_plt_section()->address() + got_offset;
+ Relocate_functions<size, false>::pcrela32(view, value, addend,
address);
- }
- break;
- }
- }
+ }
+ break;
+ }
+ }
gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
_("unsupported reloc %u"), r_type);
break;
optimized_type = tls::TLSOPT_NONE;
}
if (optimized_type == tls::TLSOPT_TO_LE)
- {
+ {
if (tls_segment == NULL)
{
gold_assert(parameters->errors()->error_count() > 0
this->tls_ld_to_le(relinfo, relnum, tls_segment, rela, r_type,
value, view, view_size);
break;
- }
+ }
else if (optimized_type == tls::TLSOPT_NONE)
- {
- // Relocate the field with the offset of the GOT entry for
- // the module index.
- unsigned int got_offset;
- got_offset = (target->got_mod_index_entry(NULL, NULL, NULL)
+ {
+ // Relocate the field with the offset of the GOT entry for
+ // the module index.
+ unsigned int got_offset;
+ got_offset = (target->got_mod_index_entry(NULL, NULL, NULL)
- target->got_size());
value = target->got_plt_section()->address() + got_offset;
- Relocate_functions<size, false>::pcrela32(view, value, addend,
+ Relocate_functions<size, false>::pcrela32(view, value, addend,
address);
- break;
- }
+ break;
+ }
gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
_("unsupported reloc %u"), r_type);
break;
break;
}
else if (optimized_type == tls::TLSOPT_NONE)
- {
- // Relocate the field with the offset of the GOT entry for
- // the tp-relative offset of the symbol.
- unsigned int got_offset;
- if (gsym != NULL)
- {
- gold_assert(gsym->has_got_offset(GOT_TYPE_TLS_OFFSET));
- got_offset = (gsym->got_offset(GOT_TYPE_TLS_OFFSET)
- - target->got_size());
- }
- else
- {
- unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
- gold_assert(object->local_has_got_offset(r_sym,
- GOT_TYPE_TLS_OFFSET));
- got_offset = (object->local_got_offset(r_sym, GOT_TYPE_TLS_OFFSET)
- - target->got_size());
- }
+ {
+ // Relocate the field with the offset of the GOT entry for
+ // the tp-relative offset of the symbol.
+ unsigned int got_offset;
+ if (gsym != NULL)
+ {
+ gold_assert(gsym->has_got_offset(GOT_TYPE_TLS_OFFSET));
+ got_offset = (gsym->got_offset(GOT_TYPE_TLS_OFFSET)
+ - target->got_size());
+ }
+ else
+ {
+ unsigned int r_sym = elfcpp::elf_r_sym<size>(rela.get_r_info());
+ gold_assert(object->local_has_got_offset(r_sym,
+ GOT_TYPE_TLS_OFFSET));
+ got_offset = (object->local_got_offset(r_sym, GOT_TYPE_TLS_OFFSET)
+ - target->got_size());
+ }
value = target->got_plt_section()->address() + got_offset;
- Relocate_functions<size, false>::pcrela32(view, value, addend,
+ Relocate_functions<size, false>::pcrela32(view, value, addend,
address);
- break;
- }
+ break;
+ }
gold_error_at_location(relinfo, relnum, rela.get_r_offset(),
_("unsupported reloc type %u"),
r_type);
tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 12);
tls::check_tls(relinfo, relnum, rela.get_r_offset(),
- (memcmp(view + 4, "\x66\x66\x48\xe8", 4) == 0));
+ (memcmp(view + 4, "\x66\x66\x48\xe8", 4) == 0));
if (size == 64)
{
tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -3);
tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 4);
tls::check_tls(relinfo, relnum, rela.get_r_offset(),
- view[-3] == 0x48 && view[-2] == 0x8d && view[-1] == 0x05);
+ view[-3] == 0x48 && view[-2] == 0x8d && view[-1] == 0x05);
view[-2] = 0x8b;
const elfcpp::Elf_Xword addend = rela.get_r_addend();
Relocate_functions<size, false>::pcrela32(view, value, addend, address);
gold_assert(r_type == elfcpp::R_X86_64_TLSDESC_CALL);
tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 2);
tls::check_tls(relinfo, relnum, rela.get_r_offset(),
- view[0] == 0xff && view[1] == 0x10);
+ view[0] == 0xff && view[1] == 0x10);
view[0] = 0x66;
view[1] = 0x90;
}
tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, -3);
tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 4);
tls::check_tls(relinfo, relnum, rela.get_r_offset(),
- view[-3] == 0x48 && view[-2] == 0x8d && view[-1] == 0x05);
+ view[-3] == 0x48 && view[-2] == 0x8d && view[-1] == 0x05);
view[-2] = 0xc7;
view[-1] = 0xc0;
value -= tls_segment->memsz();
gold_assert(r_type == elfcpp::R_X86_64_TLSDESC_CALL);
tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 2);
tls::check_tls(relinfo, relnum, rela.get_r_offset(),
- view[0] == 0xff && view[1] == 0x10);
+ view[0] == 0xff && view[1] == 0x10);
view[0] = 0x66;
view[1] = 0x90;
}
tls::check_range(relinfo, relnum, rela.get_r_offset(), view_size, 9);
tls::check_tls(relinfo, relnum, rela.get_r_offset(),
- view[-3] == 0x48 && view[-2] == 0x8d && view[-1] == 0x3d);
+ view[-3] == 0x48 && view[-2] == 0x8d && view[-1] == 0x3d);
tls::check_tls(relinfo, relnum, rela.get_r_offset(), view[4] == 0xe8);
{
// movq
if (op1 == 0x4c)
- view[-3] = 0x49;
+ view[-3] = 0x49;
view[-2] = 0xc7;
view[-1] = 0xc0 | reg;
}
{
// Special handling for %rsp.
if (op1 == 0x4c)
- view[-3] = 0x49;
+ view[-3] = 0x49;
view[-2] = 0x81;
view[-1] = 0xc0 | reg;
}
{
// addq
if (op1 == 0x4c)
- view[-3] = 0x4d;
+ view[-3] = 0x4d;
view[-2] = 0x8d;
view[-1] = 0x80 | reg | (reg << 3);
}
jmp[0] = 0xe9;
elfcpp::Swap_unaligned<32, false>::writeval(jmp + 1, length - 5);
return (std::string(reinterpret_cast<char*>(&jmp[0]), 5)
- + std::string(length - 5, static_cast<char>(0x90)));
+ + std::string(length - 5, static_cast<char>(0x90)));
}
// Nop sequences of various lengths.
const char nop2[2] = { '\x66', '\x90' }; // xchg %ax %ax
const char nop3[3] = { '\x0f', '\x1f', '\x00' }; // nop (%rax)
const char nop4[4] = { '\x0f', '\x1f', '\x40', // nop 0(%rax)
- '\x00'};
+ '\x00'};
const char nop5[5] = { '\x0f', '\x1f', '\x44', // nop 0(%rax,%rax,1)
'\x00', '\x00' };
const char nop6[6] = { '\x66', '\x0f', '\x1f', // nopw 0(%rax,%rax,1)
- '\x44', '\x00', '\x00' };
+ '\x44', '\x00', '\x00' };
const char nop7[7] = { '\x0f', '\x1f', '\x80', // nopl 0L(%rax)
- '\x00', '\x00', '\x00',
+ '\x00', '\x00', '\x00',
'\x00' };
const char nop8[8] = { '\x0f', '\x1f', '\x84', // nopl 0L(%rax,%rax,1)
- '\x00', '\x00', '\x00',
+ '\x00', '\x00', '\x00',
'\x00', '\x00' };
const char nop9[9] = { '\x66', '\x0f', '\x1f', // nopw 0L(%rax,%rax,1)
- '\x84', '\x00', '\x00',
+ '\x84', '\x00', '\x00',
'\x00', '\x00', '\x00' };
const char nop10[10] = { '\x66', '\x2e', '\x0f', // nopw %cs:0L(%rax,%rax,1)
- '\x1f', '\x84', '\x00',
+ '\x1f', '\x84', '\x00',
'\x00', '\x00', '\x00',
'\x00' };
const char nop11[11] = { '\x66', '\x66', '\x2e', // data16
- '\x0f', '\x1f', '\x84', // nopw %cs:0L(%rax,%rax,1)
+ '\x0f', '\x1f', '\x84', // nopw %cs:0L(%rax,%rax,1)
'\x00', '\x00', '\x00',
'\x00', '\x00' };
const char nop12[12] = { '\x66', '\x66', '\x66', // data16; data16
- '\x2e', '\x0f', '\x1f', // nopw %cs:0L(%rax,%rax,1)
+ '\x2e', '\x0f', '\x1f', // nopw %cs:0L(%rax,%rax,1)
'\x84', '\x00', '\x00',
'\x00', '\x00', '\x00' };
const char nop13[13] = { '\x66', '\x66', '\x66', // data16; data16; data16
- '\x66', '\x2e', '\x0f', // nopw %cs:0L(%rax,%rax,1)
+ '\x66', '\x2e', '\x0f', // nopw %cs:0L(%rax,%rax,1)
'\x1f', '\x84', '\x00',
'\x00', '\x00', '\x00',
- '\x00' };
+ '\x00' };
const char nop14[14] = { '\x66', '\x66', '\x66', // data16; data16; data16
- '\x66', '\x66', '\x2e', // data16
+ '\x66', '\x66', '\x2e', // data16
'\x0f', '\x1f', '\x84', // nopw %cs:0L(%rax,%rax,1)
'\x00', '\x00', '\x00',
- '\x00', '\x00' };
+ '\x00', '\x00' };
const char nop15[15] = { '\x66', '\x66', '\x66', // data16; data16; data16
- '\x66', '\x66', '\x66', // data16; data16
+ '\x66', '\x66', '\x66', // data16; data16
'\x2e', '\x0f', '\x1f', // nopw %cs:0L(%rax,%rax,1)
'\x84', '\x00', '\x00',
- '\x00', '\x00', '\x00' };
+ '\x00', '\x00', '\x00' };
const char* nops[16] = {
NULL,
*to = "__morestack_non_split";
}
-// The selector for x86_64 object files.
+// The selector for x86_64 object files. Note this is never instantiated
+// directly. It's only used in Target_selector_x86_64_nacl, below.
template<int size>
class Target_selector_x86_64 : public Target_selector_freebsd
public:
Target_selector_x86_64()
: Target_selector_freebsd(elfcpp::EM_X86_64, size, false,
- (size == 64
+ (size == 64
? "elf64-x86-64" : "elf32-x86-64"),
- (size == 64
+ (size == 64
? "elf64-x86-64-freebsd"
: "elf32-x86-64-freebsd"),
(size == 64 ? "elf_x86_64" : "elf32_x86_64"))
};
-Target_selector_x86_64<64> target_selector_x86_64;
-Target_selector_x86_64<32> target_selector_x32;
+// NaCl variant. It uses different PLT contents.
+
+template<int size>
+class Output_data_plt_x86_64_nacl : public Output_data_plt_x86_64<size>
+{
+ public:
+ Output_data_plt_x86_64_nacl(Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ : Output_data_plt_x86_64<size>(layout, plt_entry_size,
+ got, got_plt, got_irelative)
+ { }
+
+ Output_data_plt_x86_64_nacl(Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative,
+ unsigned int plt_count)
+ : Output_data_plt_x86_64<size>(layout, plt_entry_size,
+ got, got_plt, got_irelative,
+ plt_count)
+ { }
+
+ protected:
+ virtual unsigned int
+ do_get_plt_entry_size() const
+ { return plt_entry_size; }
+
+ virtual void
+ do_add_eh_frame(Layout* layout)
+ {
+ layout->add_eh_frame_for_plt(this,
+ this->plt_eh_frame_cie,
+ this->plt_eh_frame_cie_size,
+ plt_eh_frame_fde,
+ plt_eh_frame_fde_size);
+ }
+
+ virtual void
+ do_fill_first_plt_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_addr,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_addr);
+
+ virtual unsigned int
+ do_fill_plt_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_index);
+
+ virtual void
+ do_fill_tlsdesc_entry(unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_base,
+ unsigned int tlsdesc_got_offset,
+ unsigned int plt_offset);
+
+ private:
+ // The size of an entry in the PLT.
+ static const int plt_entry_size = 64;
+
+ // The first entry in the PLT.
+ static const unsigned char first_plt_entry[plt_entry_size];
+
+ // Other entries in the PLT for an executable.
+ static const unsigned char plt_entry[plt_entry_size];
+
+ // The reserved TLSDESC entry in the PLT for an executable.
+ static const unsigned char tlsdesc_plt_entry[plt_entry_size];
+
+ // The .eh_frame unwind information for the PLT.
+ static const int plt_eh_frame_fde_size = 32;
+ static const unsigned char plt_eh_frame_fde[plt_eh_frame_fde_size];
+};
+
+template<int size>
+class Target_x86_64_nacl : public Target_x86_64<size>
+{
+ public:
+ Target_x86_64_nacl()
+ : Target_x86_64<size>(&x86_64_nacl_info)
+ { }
+
+ virtual Output_data_plt_x86_64<size>*
+ do_make_data_plt(Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative)
+ {
+ return new Output_data_plt_x86_64_nacl<size>(layout, got, got_plt,
+ got_irelative);
+ }
+
+ virtual Output_data_plt_x86_64<size>*
+ do_make_data_plt(Layout* layout,
+ Output_data_got<64, false>* got,
+ Output_data_space* got_plt,
+ Output_data_space* got_irelative,
+ unsigned int plt_count)
+ {
+ return new Output_data_plt_x86_64_nacl<size>(layout, got, got_plt,
+ got_irelative,
+ plt_count);
+ }
+
+ private:
+ static const Target::Target_info x86_64_nacl_info;
+};
+
+template<>
+const Target::Target_info Target_x86_64_nacl<64>::x86_64_nacl_info =
+{
+ 64, // size
+ false, // is_big_endian
+ elfcpp::EM_X86_64, // machine_code
+ false, // has_make_symbol
+ false, // has_resolve
+ true, // has_code_fill
+ true, // is_default_stack_executable
+ true, // can_icf_inline_merge_sections
+ '\0', // wrap_char
+ "/lib64/ld-nacl-x86-64.so.1", // dynamic_linker
+ 0x20000, // default_text_segment_address
+ 0x10000, // abi_pagesize (overridable by -z max-page-size)
+ 0x10000, // common_pagesize (overridable by -z common-page-size)
+ true, // isolate_execinstr
+ 0x10000000, // rosegment_gap
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_X86_64_LCOMMON, // large_common_shndx
+ 0, // small_common_section_flags
+ elfcpp::SHF_X86_64_LARGE, // large_common_section_flags
+ NULL, // attributes_section
+ NULL // attributes_vendor
+};
+
+template<>
+const Target::Target_info Target_x86_64_nacl<32>::x86_64_nacl_info =
+{
+ 32, // size
+ false, // is_big_endian
+ elfcpp::EM_X86_64, // machine_code
+ false, // has_make_symbol
+ false, // has_resolve
+ true, // has_code_fill
+ true, // is_default_stack_executable
+ true, // can_icf_inline_merge_sections
+ '\0', // wrap_char
+ "/lib/ld-nacl-x86-64.so.1", // dynamic_linker
+ 0x20000, // default_text_segment_address
+ 0x10000, // abi_pagesize (overridable by -z max-page-size)
+ 0x10000, // common_pagesize (overridable by -z common-page-size)
+ true, // isolate_execinstr
+ 0x10000000, // rosegment_gap
+ elfcpp::SHN_UNDEF, // small_common_shndx
+ elfcpp::SHN_X86_64_LCOMMON, // large_common_shndx
+ 0, // small_common_section_flags
+ elfcpp::SHF_X86_64_LARGE, // large_common_section_flags
+ NULL, // attributes_section
+ NULL // attributes_vendor
+};
+
+#define NACLMASK 0xe0 // 32-byte alignment mask.
+
+// The first entry in the PLT.
+
+template<int size>
+const unsigned char
+Output_data_plt_x86_64_nacl<size>::first_plt_entry[plt_entry_size] =
+{
+ 0xff, 0x35, // pushq contents of memory address
+ 0, 0, 0, 0, // replaced with address of .got + 8
+ 0x4c, 0x8b, 0x1d, // mov GOT+16(%rip), %r11
+ 0, 0, 0, 0, // replaced with address of .got + 16
+ 0x41, 0x83, 0xe3, NACLMASK, // and $-32, %r11d
+ 0x4d, 0x01, 0xfb, // add %r15, %r11
+ 0x41, 0xff, 0xe3, // jmpq *%r11
+
+ // 9-byte nop sequence to pad out to the next 32-byte boundary.
+ 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopl %cs:0x0(%rax,%rax,1)
+
+ // 32 bytes of nop to pad out to the standard size
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, // excess data32 prefixes
+ 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopw %cs:0x0(%rax,%rax,1)
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, // excess data32 prefixes
+ 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopw %cs:0x0(%rax,%rax,1)
+ 0x66, // excess data32 prefix
+ 0x90 // nop
+};
+
+template<int size>
+void
+Output_data_plt_x86_64_nacl<size>::do_fill_first_plt_entry(
+ unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address)
+{
+ memcpy(pov, first_plt_entry, plt_entry_size);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
+ (got_address + 8
+ - (plt_address + 2 + 4)));
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 9,
+ (got_address + 16
+ - (plt_address + 9 + 4)));
+}
+
+// Subsequent entries in the PLT.
+
+template<int size>
+const unsigned char
+Output_data_plt_x86_64_nacl<size>::plt_entry[plt_entry_size] =
+{
+ 0x4c, 0x8b, 0x1d, // mov name@GOTPCREL(%rip),%r11
+ 0, 0, 0, 0, // replaced with address of symbol in .got
+ 0x41, 0x83, 0xe3, NACLMASK, // and $-32, %r11d
+ 0x4d, 0x01, 0xfb, // add %r15, %r11
+ 0x41, 0xff, 0xe3, // jmpq *%r11
+
+ // 15-byte nop sequence to pad out to the next 32-byte boundary.
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, // excess data32 prefixes
+ 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopw %cs:0x0(%rax,%rax,1)
+
+ // Lazy GOT entries point here (32-byte aligned).
+ 0x68, // pushq immediate
+ 0, 0, 0, 0, // replaced with index into relocation table
+ 0xe9, // jmp relative
+ 0, 0, 0, 0, // replaced with offset to start of .plt0
+
+ // 22 bytes of nop to pad out to the standard size.
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, // excess data32 prefixes
+ 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopw %cs:0x0(%rax,%rax,1)
+ 0x0f, 0x1f, 0x80, 0, 0, 0, 0, // nopl 0x0(%rax)
+};
+
+template<int size>
+unsigned int
+Output_data_plt_x86_64_nacl<size>::do_fill_plt_entry(
+ unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ unsigned int got_offset,
+ unsigned int plt_offset,
+ unsigned int plt_index)
+{
+ memcpy(pov, plt_entry, plt_entry_size);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 3,
+ (got_address + got_offset
+ - (plt_address + plt_offset
+ + 3 + 4)));
+
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 33, plt_index);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 38,
+ - (plt_offset + 38 + 4));
+
+ return 32;
+}
+
+// The reserved TLSDESC entry in the PLT.
+
+template<int size>
+const unsigned char
+Output_data_plt_x86_64_nacl<size>::tlsdesc_plt_entry[plt_entry_size] =
+{
+ 0xff, 0x35, // pushq x(%rip)
+ 0, 0, 0, 0, // replaced with address of linkmap GOT entry (at PLTGOT + 8)
+ 0x4c, 0x8b, 0x1d, // mov y(%rip),%r11
+ 0, 0, 0, 0, // replaced with offset of reserved TLSDESC_GOT entry
+ 0x41, 0x83, 0xe3, NACLMASK, // and $-32, %r11d
+ 0x4d, 0x01, 0xfb, // add %r15, %r11
+ 0x41, 0xff, 0xe3, // jmpq *%r11
+
+ // 41 bytes of nop to pad out to the standard size.
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, // excess data32 prefixes
+ 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopw %cs:0x0(%rax,%rax,1)
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, // excess data32 prefixes
+ 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopw %cs:0x0(%rax,%rax,1)
+ 0x66, 0x66, // excess data32 prefixes
+ 0x2e, 0x0f, 0x1f, 0x84, 0, 0, 0, 0, 0, // nopw %cs:0x0(%rax,%rax,1)
+};
+
+template<int size>
+void
+Output_data_plt_x86_64_nacl<size>::do_fill_tlsdesc_entry(
+ unsigned char* pov,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr plt_address,
+ typename elfcpp::Elf_types<size>::Elf_Addr got_base,
+ unsigned int tlsdesc_got_offset,
+ unsigned int plt_offset)
+{
+ memcpy(pov, tlsdesc_plt_entry, plt_entry_size);
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 2,
+ (got_address + 8
+ - (plt_address + plt_offset
+ + 2 + 4)));
+ elfcpp::Swap_unaligned<32, false>::writeval(pov + 9,
+ (got_base
+ + tlsdesc_got_offset
+ - (plt_address + plt_offset
+ + 9 + 4)));
+}
+
+// The .eh_frame unwind information for the PLT.
+
+template<int size>
+const unsigned char
+Output_data_plt_x86_64_nacl<size>::plt_eh_frame_fde[plt_eh_frame_fde_size] =
+{
+ 0, 0, 0, 0, // Replaced with offset to .plt.
+ 0, 0, 0, 0, // Replaced with size of .plt.
+ 0, // Augmentation size.
+ elfcpp::DW_CFA_def_cfa_offset, 16, // DW_CFA_def_cfa_offset: 16.
+ elfcpp::DW_CFA_advance_loc + 6, // Advance 6 to __PLT__ + 6.
+ elfcpp::DW_CFA_def_cfa_offset, 24, // DW_CFA_def_cfa_offset: 24.
+ elfcpp::DW_CFA_advance_loc + 58, // Advance 58 to __PLT__ + 64.
+ elfcpp::DW_CFA_def_cfa_expression, // DW_CFA_def_cfa_expression.
+ 13, // Block length.
+ elfcpp::DW_OP_breg7, 8, // Push %rsp + 8.
+ elfcpp::DW_OP_breg16, 0, // Push %rip.
+ elfcpp::DW_OP_const1u, 63, // Push 0x3f.
+ elfcpp::DW_OP_and, // & (%rip & 0x3f).
+ elfcpp::DW_OP_const1u, 37, // Push 0x25.
+ elfcpp::DW_OP_ge, // >= ((%rip & 0x3f) >= 0x25)
+ elfcpp::DW_OP_lit3, // Push 3.
+ elfcpp::DW_OP_shl, // << (((%rip & 0x3f) >= 0x25) << 3)
+ elfcpp::DW_OP_plus, // + ((((%rip&0x3f)>=0x25)<<3)+%rsp+8
+ elfcpp::DW_CFA_nop, // Align to 32 bytes.
+ elfcpp::DW_CFA_nop
+};
+
+// The selector for x86_64-nacl object files.
+
+template<int size>
+class Target_selector_x86_64_nacl
+ : public Target_selector_nacl<Target_selector_x86_64<size>,
+ Target_x86_64_nacl<size> >
+{
+ public:
+ Target_selector_x86_64_nacl()
+ : Target_selector_nacl<Target_selector_x86_64<size>,
+ Target_x86_64_nacl<size> >("x86-64",
+ size == 64
+ ? "elf64-x86-64-nacl"
+ : "elf32-x86-64-nacl",
+ size == 64
+ ? "elf_x86_64_nacl"
+ : "elf32_x86_64_nacl")
+ { }
+};
+
+Target_selector_x86_64_nacl<64> target_selector_x86_64;
+Target_selector_x86_64_nacl<32> target_selector_x32;
} // End anonymous namespace.