diff options
-rw-r--r-- | ChangeLog | 7 | ||||
-rwxr-xr-x | configure | 2 | ||||
-rw-r--r-- | configure.ac | 46 | ||||
-rw-r--r-- | gold/ChangeLog | 364 | ||||
-rw-r--r-- | gold/Makefile.am | 2 | ||||
-rw-r--r-- | gold/Makefile.in | 19 | ||||
-rw-r--r-- | gold/arm.cc | 1216 | ||||
-rw-r--r-- | gold/freebsd.h | 6 | ||||
-rw-r--r-- | gold/gold.cc | 152 | ||||
-rw-r--r-- | gold/i386.cc | 1615 | ||||
-rw-r--r-- | gold/incremental.cc | 207 | ||||
-rw-r--r-- | gold/layout.cc | 463 | ||||
-rw-r--r-- | gold/layout.h | 35 | ||||
-rw-r--r-- | gold/nacl.cc | 46 | ||||
-rw-r--r-- | gold/nacl.h | 243 | ||||
-rw-r--r-- | gold/object.cc | 624 | ||||
-rw-r--r-- | gold/parameters.cc | 8 | ||||
-rw-r--r-- | gold/powerpc.cc | 210 | ||||
-rw-r--r-- | gold/sparc.cc | 326 | ||||
-rw-r--r-- | gold/target-select.cc | 11 | ||||
-rw-r--r-- | gold/target-select.h | 14 | ||||
-rw-r--r-- | gold/target.h | 29 | ||||
-rw-r--r-- | gold/testsuite/testfile.cc | 14 | ||||
-rw-r--r-- | gold/x86_64.cc | 1588 |
24 files changed, 4647 insertions, 2600 deletions
@@ -1,3 +1,8 @@ +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. @@ -586,7 +591,7 @@ * 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. @@ -2869,7 +2869,7 @@ case "${ENABLE_GOLD}" in *-*-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*) ;; diff --git a/configure.ac b/configure.ac index c279587..396c87b 100644 --- a/configure.ac +++ b/configure.ac @@ -112,11 +112,11 @@ extra_host_args= ### 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 @@ -209,7 +209,7 @@ if test x"${host}" = x"${target}" ; then is_cross_compiler=no else is_cross_compiler=yes -fi +fi # Find the build and target subdir names. GCC_TOPLEV_SUBDIRS @@ -245,7 +245,7 @@ if test x$with_system_zlib = xyes ; then 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 @@ -253,7 +253,7 @@ 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 @@ -313,7 +313,7 @@ case "${ENABLE_GOLD}" in *-*-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*) ;; @@ -379,7 +379,7 @@ esac # 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. @@ -689,7 +689,7 @@ case "${target}" in ;; *-*-lynxos*) noconfigdirs="$noconfigdirs ${libgcj}" - ;; + ;; esac # Default libgloss CPU subdirectory. @@ -774,7 +774,7 @@ case "${target}" in ;; *-*-lynxos*) noconfigdirs="$noconfigdirs target-newlib target-libgloss" - ;; + ;; *-*-mingw*) noconfigdirs="$noconfigdirs target-newlib target-libgloss" ;; @@ -1078,7 +1078,7 @@ case "${host}" in hppa*-hp-hpux*) host_makefile_frag="config/mh-pa" ;; - hppa*-*) + hppa*-*) host_makefile_frag="config/mh-pa" ;; *-*-darwin*) @@ -1774,7 +1774,7 @@ if test -d ${srcdir}/gcc; then # 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= @@ -2019,7 +2019,7 @@ done 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 @@ -2036,7 +2036,7 @@ done 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 @@ -2087,7 +2087,7 @@ ACX_TOOL_DIRS 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 @@ -2178,11 +2178,11 @@ fi # 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, @@ -2283,7 +2283,7 @@ case "${target}" in 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" @@ -2357,7 +2357,7 @@ if test $? = 0 ; then 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." @@ -2727,7 +2727,7 @@ baseargs=`echo "x$baseargs" | sed -e 's/^x *//' -e 's,\\$,$$,g'` # --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 @@ -3052,7 +3052,7 @@ AC_SUBST(CFLAGS) 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 @@ -3157,7 +3157,7 @@ if test "$USE_MAINTAINER_MODE" = yes; then else MAINTAINER_MODE_TRUE='#' MAINTAINER_MODE_FALSE= -fi +fi MAINT=$MAINTAINER_MODE_TRUE AC_SUBST(MAINT)dnl diff --git a/gold/ChangeLog b/gold/ChangeLog index 888affd..a0a461f 100644 --- a/gold/ChangeLog +++ b/gold/ChangeLog @@ -1,3 +1,199 @@ +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) @@ -304,7 +500,7 @@ 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 @@ -2008,7 +2204,7 @@ * 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 @@ -2495,7 +2691,7 @@ * 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. @@ -3251,9 +3447,9 @@ 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> @@ -3542,7 +3738,7 @@ 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 @@ -3550,7 +3746,7 @@ (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 @@ -3609,7 +3805,7 @@ 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> @@ -3636,43 +3832,43 @@ 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> @@ -4707,7 +4903,7 @@ 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 @@ -4719,7 +4915,7 @@ 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 @@ -5078,15 +5274,15 @@ 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. @@ -5104,12 +5300,12 @@ 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_, @@ -5385,7 +5581,7 @@ 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. @@ -5556,7 +5752,7 @@ 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. @@ -5622,13 +5818,13 @@ 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. @@ -5644,10 +5840,10 @@ 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. @@ -5850,7 +6046,7 @@ 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. @@ -5862,7 +6058,7 @@ (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. @@ -5900,7 +6096,7 @@ * 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, @@ -5954,7 +6150,7 @@ (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. @@ -6296,8 +6492,8 @@ * 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. @@ -6416,14 +6612,14 @@ * 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. @@ -6435,7 +6631,7 @@ (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. @@ -6527,11 +6723,11 @@ (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 @@ -6803,7 +6999,7 @@ 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. @@ -7514,7 +7710,7 @@ (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, @@ -8505,7 +8701,7 @@ 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. @@ -8931,7 +9127,7 @@ 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 @@ -9158,7 +9354,7 @@ 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. @@ -9419,7 +9615,7 @@ * 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. @@ -10345,11 +10541,11 @@ 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> @@ -10389,7 +10585,7 @@ 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> diff --git a/gold/Makefile.am b/gold/Makefile.am index 7d4b725..72ffdf5 100644 --- a/gold/Makefile.am +++ b/gold/Makefile.am @@ -64,6 +64,7 @@ CCFILES = \ layout.cc \ mapfile.cc \ merge.cc \ + nacl.cc \ object.cc \ options.cc \ output.cc \ @@ -111,6 +112,7 @@ HFILES = \ layout.h \ mapfile.h \ merge.h \ + nacl.h \ object.h \ options.h \ output.h \ diff --git a/gold/Makefile.in b/gold/Makefile.in index 2998b7b..356b1d6 100644 --- a/gold/Makefile.in +++ b/gold/Makefile.in @@ -52,6 +52,7 @@ DIST_COMMON = NEWS README ChangeLog $(srcdir)/Makefile.in \ 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 \ @@ -80,13 +81,14 @@ am__objects_1 = archive.$(OBJEXT) attributes.$(OBJEXT) \ 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) \ @@ -408,6 +410,7 @@ CCFILES = \ layout.cc \ mapfile.cc \ merge.cc \ + nacl.cc \ object.cc \ options.cc \ output.cc \ @@ -455,6 +458,7 @@ HFILES = \ layout.h \ mapfile.h \ merge.h \ + nacl.h \ object.h \ options.h \ output.h \ @@ -664,6 +668,7 @@ distclean-compile: @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@ diff --git a/gold/arm.cc b/gold/arm.cc index 1ddbf7f..92735ea 100644 --- a/gold/arm.cc +++ b/gold/arm.cc @@ -51,6 +51,7 @@ #include "gc.h" #include "attributes.h" #include "arm-reloc-property.h" +#include "nacl.h" namespace { @@ -61,6 +62,9 @@ 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; template<bool big_endian> @@ -107,7 +111,7 @@ const size_t ARM_TCB_SIZE = 8; // // 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 @@ -138,7 +142,7 @@ class Insn_template 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. @@ -152,24 +156,24 @@ class Insn_template 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) @@ -181,7 +185,7 @@ class Insn_template 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. @@ -270,7 +274,7 @@ typedef enum 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; @@ -312,7 +316,7 @@ class Stub_template unsigned alignment() const { return this->alignment_; } - + // Return whether entry point is in thumb mode. bool entry_in_thumb_mode() const @@ -349,7 +353,7 @@ class Stub_template // 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. @@ -364,7 +368,7 @@ class Stub_template 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_; }; @@ -405,7 +409,7 @@ class Stub 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 @@ -437,7 +441,7 @@ class Stub 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 @@ -550,7 +554,7 @@ class Reloc_stub : public Stub // 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_) @@ -600,7 +604,7 @@ class Reloc_stub : public Stub 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. @@ -641,7 +645,7 @@ class Reloc_stub : public Stub // 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 @@ -715,15 +719,15 @@ class Cortex_a8_stub : public Stub { 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_; } } @@ -850,13 +854,13 @@ class Stub_factory 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]; }; @@ -970,7 +974,7 @@ class Stub_table : public Output_data // 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>*, @@ -981,7 +985,7 @@ class Stub_table : public Output_data // Write out section contents. void do_write(Output_file*); - + // Return the required alignment. uint64_t do_addralign() const @@ -996,7 +1000,7 @@ class Stub_table : public Output_data void set_final_data_size() { this->set_data_size(this->current_data_size()); } - + private: // Relocate one stub. void @@ -1074,7 +1078,7 @@ class Arm_exidx_cantunwind : public Output_section_data 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. @@ -1083,7 +1087,7 @@ class Arm_exidx_cantunwind : public Output_section_data // 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; @@ -1132,7 +1136,7 @@ class Arm_exidx_merged_section : public Output_relaxed_input_section 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_; @@ -1156,7 +1160,7 @@ class Arm_input_section : public Output_relaxed_input_section // Initialize. void init(); - + // Whether this is a stub table owner. bool is_stub_table_owner() const @@ -1211,7 +1215,7 @@ class Arm_input_section : public Output_relaxed_input_section 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()) @@ -1272,7 +1276,7 @@ class Arm_exidx_fixup 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 @@ -1356,7 +1360,7 @@ class Arm_output_section : public Output_section ~Arm_output_section() { } - + // Group input sections for stub generation. void group_sections(section_size_type, bool, Target_arm<big_endian>*, const Task*); @@ -1416,7 +1420,7 @@ class Arm_exidx_input_section ~Arm_exidx_input_section() { } - + // Accessors: This is a read-only class. // Return the object containing this EXIDX input section. @@ -1485,7 +1489,7 @@ class Arm_relobj : public Sized_relobj_file<32, big_endian> 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_(), @@ -1496,7 +1500,7 @@ class Arm_relobj : public Sized_relobj_file<32, big_endian> ~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 @@ -1521,7 +1525,7 @@ class Arm_relobj : public Sized_relobj_file<32, big_endian> 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*, @@ -1569,7 +1573,7 @@ class Arm_relobj : public Sized_relobj_file<32, big_endian> || (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, @@ -1578,11 +1582,11 @@ class Arm_relobj : public Sized_relobj_file<32, big_endian> // 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) @@ -1625,7 +1629,7 @@ class Arm_relobj : public Sized_relobj_file<32, big_endian> 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(); @@ -1634,7 +1638,7 @@ class Arm_relobj : public Sized_relobj_file<32, big_endian> 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 @@ -1647,7 +1651,7 @@ class Arm_relobj : public Sized_relobj_file<32, big_endian> 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()); } @@ -1667,7 +1671,7 @@ class Arm_relobj : public Sized_relobj_file<32, big_endian> // Count the local symbols. void do_count_local_symbols(Stringpool_template<char>*, - Stringpool_template<char>*); + Stringpool_template<char>*); void do_relocate_sections( @@ -1769,7 +1773,7 @@ class Arm_dynobj : public Sized_dynobj<32, big_endian> : 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_; } @@ -1862,13 +1866,13 @@ class Cortex_a8_reloc { } // 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 @@ -2076,7 +2080,7 @@ class Arm_scan_relocatable_relocs : 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: @@ -2113,10 +2117,10 @@ class Target_arm : public Sized_target<32, big_endian> // 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), @@ -2133,7 +2137,7 @@ class Target_arm : public Sized_target<32, big_endian> void set_should_force_pic_veneer(bool value) { this->should_force_pic_veneer_ = value; } - + // Whether we use THUMB-2 instructions. bool using_thumb2() const @@ -2196,7 +2200,7 @@ class Target_arm : public Sized_target<32, big_endian> 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 @@ -2215,8 +2219,8 @@ class Target_arm : public Sized_target<32, big_endian> && 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, @@ -2311,7 +2315,7 @@ class Target_arm : public Sized_target<32, big_endian> 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 @@ -2358,7 +2362,7 @@ class Target_arm : public Sized_target<32, big_endian> // // Methods to support stub-generations. // - + // Return the stub factory const Stub_factory& stub_factory() const @@ -2384,12 +2388,12 @@ class Target_arm : public Sized_target<32, big_endian> 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() @@ -2440,6 +2444,11 @@ class Target_arm : public Sized_target<32, big_endian> 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, @@ -2514,10 +2523,16 @@ class Target_arm : public Sized_target<32, big_endian> && !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 @@ -2548,19 +2563,19 @@ class Target_arm : public Sized_target<32, big_endian> 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: @@ -2667,7 +2682,7 @@ class Target_arm : public Sized_target<32, big_endian> // 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); @@ -2862,7 +2877,7 @@ class Target_arm : public Sized_target<32, big_endian> 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; @@ -2915,6 +2930,8 @@ const Target::Target_info Target_arm<big_endian>::arm_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 @@ -2943,10 +2960,10 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> // 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 | // +-------+---------------+-------+-------+-----------------------+ @@ -2977,10 +2994,10 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> // 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 | // +---------+-+-----------+-------++-+-----+-------+---------------+ @@ -3128,9 +3145,9 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> 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. @@ -3319,7 +3336,7 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> 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 @@ -3339,7 +3356,7 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> 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 @@ -3472,7 +3489,7 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> 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); } @@ -3549,7 +3566,7 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> 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) @@ -3604,7 +3621,7 @@ class Arm_relocate_functions : public Relocate_functions<32, big_endian> 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 @@ -3849,9 +3866,9 @@ Arm_relocate_functions<big_endian>::arm_branch_common( 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); @@ -3902,7 +3919,7 @@ Arm_relocate_functions<big_endian>::arm_branch_common( 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; @@ -3984,7 +4001,7 @@ Arm_relocate_functions<big_endian>::thumb_branch_common( // 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) { @@ -4007,7 +4024,7 @@ Arm_relocate_functions<big_endian>::thumb_branch_common( 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; } @@ -4036,7 +4053,7 @@ Arm_relocate_functions<big_endian>::thumb_branch_common( } return This::STATUS_OKAY; } - + int32_t addend = This::thumb32_branch_offset(upper_insn, lower_insn); Arm_address branch_target = psymval->value(object, addend); @@ -4075,7 +4092,7 @@ Arm_relocate_functions<big_endian>::thumb_branch_common( 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; } @@ -4301,11 +4318,11 @@ Stub_template::Stub_template( 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 @@ -4323,7 +4340,7 @@ Stub_template::Stub_template( default: gold_unreachable(); } - offset += insn_size; + offset += insn_size; } this->size_ = offset; } @@ -4360,7 +4377,7 @@ Stub::do_fixed_endian_write(unsigned char* view, section_size_type view_size) 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()); @@ -4371,7 +4388,7 @@ Stub::do_fixed_endian_write(unsigned char* view, section_size_type view_size) pov += insns[i].size(); } gold_assert(static_cast<section_size_type>(pov - view) == view_size); -} +} // Reloc_stub::Key methods. @@ -4460,7 +4477,7 @@ Reloc_stub::stub_type_for_reloc( 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) @@ -4511,7 +4528,7 @@ Reloc_stub::stub_type_for_reloc( else { // Thumb to arm. - + // FIXME: We should check that the input section is from an // object that has interwork enabled. @@ -4612,16 +4629,16 @@ Stub_factory::Stub_factory() { // 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[] = @@ -4629,9 +4646,9 @@ Stub_factory::Stub_factory() 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[] = { @@ -4642,9 +4659,9 @@ Stub_factory::Stub_factory() 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[] = @@ -4654,9 +4671,9 @@ Stub_factory::Stub_factory() 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[] = @@ -4665,9 +4682,9 @@ Stub_factory::Stub_factory() 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[] = @@ -4676,7 +4693,7 @@ Stub_factory::Stub_factory() 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[] = @@ -4684,9 +4701,9 @@ Stub_factory::Stub_factory() 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 @@ -4697,9 +4714,9 @@ Stub_factory::Stub_factory() 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[] = { @@ -4707,9 +4724,9 @@ Stub_factory::Stub_factory() 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[] = { @@ -4718,9 +4735,9 @@ Stub_factory::Stub_factory() 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[] = @@ -4732,9 +4749,9 @@ Stub_factory::Stub_factory() 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[] = @@ -4745,14 +4762,14 @@ Stub_factory::Stub_factory() 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 @@ -4763,21 +4780,21 @@ Stub_factory::Stub_factory() 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. @@ -4998,7 +5015,7 @@ Stub_table<big_endian>::update_data_size_and_addralign() // 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; @@ -5132,7 +5149,7 @@ Arm_input_section<big_endian>::do_write(Output_file* of) // 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()) @@ -5191,7 +5208,7 @@ Arm_exidx_cantunwind::do_fixed_endian_write(Output_file* of) 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_); @@ -5209,7 +5226,7 @@ Arm_exidx_cantunwind::do_fixed_endian_write(Output_file* of) { 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()); @@ -5289,7 +5306,7 @@ Arm_exidx_merged_section::build_contents( 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) { @@ -5361,7 +5378,7 @@ Arm_exidx_merged_section::do_output_offset( // Offset is discarded owing to EXIDX entry merging. *poutput = -1; } - + return true; } @@ -5373,7 +5390,7 @@ Arm_exidx_merged_section::do_write(Output_file* of) 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); @@ -5484,7 +5501,7 @@ Arm_exidx_fixup::process_exidx_section( 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); @@ -5517,7 +5534,7 @@ Arm_exidx_fixup::process_exidx_section( 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) @@ -5526,7 +5543,7 @@ Arm_exidx_fixup::process_exidx_section( *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 @@ -5559,14 +5576,14 @@ Arm_output_section<big_endian>::create_stub_group( // 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()) { @@ -5590,7 +5607,7 @@ Arm_output_section<big_endian>::create_stub_group( 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; @@ -5615,7 +5632,7 @@ Arm_output_section<big_endian>::create_stub_group( // 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. @@ -5666,8 +5683,8 @@ Arm_output_section<big_endian>::group_sections( 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) { @@ -5679,7 +5696,7 @@ Arm_output_section<big_endian>::group_sections( 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, @@ -5712,7 +5729,7 @@ Arm_output_section<big_endian>::group_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 @@ -5809,7 +5826,7 @@ Arm_output_section<big_endian>::fix_exidx_coverage( 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*, @@ -5879,12 +5896,12 @@ Arm_output_section<big_endian>::fix_exidx_coverage( 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); @@ -5928,7 +5945,7 @@ Arm_output_section<big_endian>::fix_exidx_coverage( 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. @@ -5963,7 +5980,7 @@ Arm_output_section<big_endian>::fix_exidx_coverage( 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()); @@ -6170,7 +6187,7 @@ Arm_relobj<big_endian>::scan_section_for_cortex_a8_erratum( // 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) { @@ -6189,7 +6206,7 @@ Arm_relobj<big_endian>::scan_section_for_cortex_a8_erratum( 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)) { @@ -6200,7 +6217,7 @@ Arm_relobj<big_endian>::scan_section_for_cortex_a8_erratum( } } - p = next; + p = next; } } @@ -6316,7 +6333,7 @@ Arm_relobj<big_endian>::scan_sections_for_stubs( // 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 @@ -6326,7 +6343,7 @@ Arm_relobj<big_endian>::do_count_local_symbols( { // 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(); @@ -6363,7 +6380,7 @@ Arm_relobj<big_endian>::do_count_local_symbols( 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 = @@ -6423,7 +6440,7 @@ Arm_relobj<big_endian>::do_relocate_sections( { // 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()) @@ -6471,7 +6488,7 @@ Arm_relobj<big_endian>::do_relocate_sections( 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); } @@ -6529,7 +6546,7 @@ Arm_relobj<big_endian>::find_linked_text_section( 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) @@ -6537,10 +6554,10 @@ Arm_relobj<big_endian>::find_linked_text_section( 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) @@ -6616,7 +6633,7 @@ Arm_relobj<big_endian>::make_exidx_input_section( 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 = @@ -6707,7 +6724,7 @@ Arm_relobj<big_endian>::do_read_symbols(Read_symbols_data* sd) 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()); @@ -6742,7 +6759,7 @@ Arm_relobj<big_endian>::do_read_symbols(Read_symbols_data* sd) 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()) { @@ -6788,7 +6805,7 @@ Arm_relobj<big_endian>::do_read_symbols(Read_symbols_data* sd) 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]; @@ -6806,7 +6823,7 @@ Arm_relobj<big_endian>::do_read_symbols(Read_symbols_data* sd) } // 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 @@ -6825,7 +6842,7 @@ Arm_relobj<big_endian>::do_gc_process_relocs(Symbol_table* symtab, // 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(), @@ -6930,7 +6947,7 @@ Arm_relobj<big_endian>::update_output_local_symbol_count() // that is discarded due to entry merging. lv.set_no_output_symtab_entry(); continue; - } + } } } @@ -6994,7 +7011,7 @@ Stub_addend_reader<elfcpp::SHT_REL, big_endian>::operator()( 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: @@ -7052,7 +7069,7 @@ Arm_output_data_got<big_endian>::add_tls_gd32_with_static_reloc( // 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, @@ -7076,8 +7093,8 @@ Arm_output_data_got<big_endian>::add_tls_gd32_with_static_reloc( 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)); } @@ -7101,7 +7118,7 @@ Arm_output_data_got<big_endian>::do_write(Output_file* of) 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 = @@ -7110,7 +7127,7 @@ Arm_output_data_got<big_endian>::do_write(Output_file* of) 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()) { @@ -7133,7 +7150,7 @@ Arm_output_data_got<big_endian>::do_write(Output_file* of) reloc.index(), reloc.relobj()->name().c_str()); continue; } - + value = psymval->value(object, 0); } else @@ -7189,6 +7206,9 @@ Arm_output_data_got<big_endian>::do_write(Output_file* of) } // 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 @@ -7197,7 +7217,7 @@ 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 @@ -7214,16 +7234,49 @@ class Output_data_plt_arm : public Output_section_data { 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); @@ -7233,18 +7286,12 @@ class Output_data_plt_arm : public Output_section_data { 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. @@ -7265,8 +7312,9 @@ class Output_data_plt_arm : public Output_section_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, @@ -7291,8 +7339,8 @@ Output_data_plt_arm<big_endian>::add_entry(Symbol* gsym) // 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_; @@ -7313,6 +7361,45 @@ Output_data_plt_arm<big_endian>::add_entry(Symbol* gsym) // 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 @@ -7320,25 +7407,63 @@ Output_data_plt_arm<big_endian>::add_entry(Symbol* gsym) // 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. @@ -7362,46 +7487,29 @@ Output_data_plt_arm<big_endian>::do_write(Output_file* of) 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); @@ -7429,7 +7537,8 @@ Target_arm<big_endian>::make_plt_entry(Symbol_table* symtab, Layout* layout, // 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), @@ -7455,7 +7564,7 @@ template<bool big_endian> 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. @@ -7464,7 +7573,7 @@ template<bool big_endian> 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. @@ -7774,8 +7883,8 @@ Target_arm<big_endian>::Scan::local(Symbol_table* symtab, { 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()); @@ -7797,16 +7906,16 @@ Target_arm<big_endian>::Scan::local(Symbol_table* symtab, // 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, @@ -7818,8 +7927,8 @@ Target_arm<big_endian>::Scan::local(Symbol_table* symtab, rel_dyn->add_local_section(object, shndx, r_type, output_section, data_shndx, reloc.get_r_offset()); - } - } + } + } break; case elfcpp::R_ARM_REL32: @@ -7936,18 +8045,18 @@ Target_arm<big_endian>::Scan::local(Symbol_table* symtab, { 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); @@ -7975,8 +8084,8 @@ Target_arm<big_endian>::Scan::local(Symbol_table* symtab, 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. @@ -8019,9 +8128,9 @@ Target_arm<big_endian>::Scan::local(Symbol_table* symtab, 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, @@ -8167,42 +8276,42 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab, 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; @@ -8211,7 +8320,7 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab, // 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: @@ -8368,16 +8477,16 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab, { 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), @@ -8394,8 +8503,8 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab, 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. @@ -8434,11 +8543,11 @@ Target_arm<big_endian>::Scan::global(Symbol_table* symtab, 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; @@ -8557,7 +8666,7 @@ Target_arm<big_endian>::do_finalize_sections( arm_relobj->attributes_section_data()); merged_any_attributes = true; } - } + } for (Input_objects::Dynobj_iterator p = input_objects->dynobj_begin(); p != input_objects->dynobj_end(); @@ -8588,22 +8697,22 @@ Target_arm<big_endian>::do_finalize_sections( { // 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 @@ -8623,21 +8732,21 @@ Target_arm<big_endian>::do_finalize_sections( 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 @@ -8828,8 +8937,8 @@ Target_arm<big_endian>::Relocate::relocate( } 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; @@ -8845,14 +8954,14 @@ Target_arm<big_endian>::Relocate::relocate( // 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. @@ -8903,9 +9012,9 @@ Target_arm<big_endian>::Relocate::relocate( 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(); @@ -8957,7 +9066,7 @@ Target_arm<big_endian>::Relocate::relocate( 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: @@ -8997,7 +9106,7 @@ Target_arm<big_endian>::Relocate::relocate( 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); @@ -9066,7 +9175,7 @@ Target_arm<big_endian>::Relocate::relocate( && !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; @@ -9257,50 +9366,50 @@ Target_arm<big_endian>::Relocate::relocate_tls( 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 @@ -9309,51 +9418,51 @@ Target_arm<big_endian>::Relocate::relocate_tls( 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(); } @@ -9582,10 +9691,10 @@ Target_arm<big_endian>::relocate_special_relocatable( 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; } @@ -9597,7 +9706,7 @@ Target_arm<big_endian>::relocate_special_relocatable( { 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); @@ -9619,14 +9728,14 @@ Target_arm<big_endian>::relocate_special_relocatable( 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 = @@ -9684,7 +9793,7 @@ Target_arm<big_endian>::relocate_special_relocatable( 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; @@ -9945,21 +10054,21 @@ Target_arm<big_endian>::do_make_elf_object( || (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; } } @@ -10254,7 +10363,7 @@ Target_arm<big_endian>::tag_cpu_name_value(unsigned int value) 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 @@ -10284,7 +10393,7 @@ Target_arm<big_endian>::merge_object_attributes( { 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"), @@ -10314,7 +10423,7 @@ Target_arm<big_endian>::merge_object_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); } @@ -10634,19 +10743,19 @@ Target_arm<big_endian>::merge_object_attributes( // 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: @@ -10659,7 +10768,7 @@ Target_arm<big_endian>::merge_object_attributes( != in_attr[i].int_value()) { gold_error(_("%s has has both the current and legacy " - "Tag_MPextension_use attributes"), + "Tag_MPextension_use attributes"), name); } } @@ -10755,7 +10864,7 @@ Target_arm<big_endian>::merge_object_attributes( 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() @@ -10833,7 +10942,7 @@ Target_arm<big_endian>::new_arm_input_section( // 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 @@ -10930,7 +11039,7 @@ Target_arm<big_endian>::scan_reloc_for_stub( 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); @@ -10964,10 +11073,10 @@ Target_arm<big_endian>::scan_reloc_for_stub( 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); @@ -11055,13 +11164,13 @@ Target_arm<big_endian>::scan_reloc_section_for_stubs( // 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 = @@ -11100,7 +11209,7 @@ Target_arm<big_endian>::scan_reloc_section_for_stubs( { // 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); } @@ -11125,11 +11234,11 @@ Target_arm<big_endian>::scan_reloc_section_for_stubs( 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 = @@ -11145,7 +11254,7 @@ Target_arm<big_endian>::scan_reloc_section_for_stubs( 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 @@ -11164,7 +11273,7 @@ Target_arm<big_endian>::scan_reloc_section_for_stubs( else { // We cannot determine the final value. - continue; + continue; } } } @@ -11385,7 +11494,7 @@ Target_arm<big_endian>::do_relax( } 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 = @@ -11449,7 +11558,7 @@ Target_arm<big_endian>::do_relax( ++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(); @@ -11665,16 +11774,16 @@ Target_arm<big_endian>::scan_span_for_cortex_a8_erratum( // 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. @@ -11729,7 +11838,7 @@ Target_arm<big_endian>::scan_span_for_cortex_a8_erratum( 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 @@ -11766,17 +11875,17 @@ Target_arm<big_endian>::scan_span_for_cortex_a8_erratum( 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, @@ -11786,9 +11895,9 @@ Target_arm<big_endian>::scan_span_for_cortex_a8_erratum( 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; @@ -11846,6 +11955,9 @@ Target_arm<big_endian>::apply_cortex_a8_workaround( 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 { @@ -11919,7 +12031,7 @@ Target_arm<big_endian>::fix_exidx_coverage( 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); @@ -11954,7 +12066,7 @@ Target_arm<big_endian>::do_define_standard_symbols( NULL, // version Symbol_table::PREDEFINED, exidx_section, - 0, // value + 0, // value 0, // symsize elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL, @@ -11968,19 +12080,229 @@ Target_arm<big_endian>::do_define_standard_symbols( // 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. diff --git a/gold/freebsd.h b/gold/freebsd.h index 175dd05..3bdedce 100644 --- a/gold/freebsd.h +++ b/gold/freebsd.h @@ -1,6 +1,6 @@ // 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. @@ -48,14 +48,14 @@ class Target_selector_freebsd : public Target_selector // 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) diff --git a/gold/gold.cc b/gold/gold.cc index f810bf9..013702f 100644 --- a/gold/gold.cc +++ b/gold/gold.cc @@ -1,6 +1,7 @@ // 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. @@ -136,7 +137,7 @@ Middle_runner::run(Workqueue* workqueue, const Task* task) // 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, @@ -161,9 +162,9 @@ class Gc_runner : public Task_function_runner 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. @@ -287,21 +288,21 @@ queue_initial_tasks(const General_options& options, { 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")); } } @@ -467,12 +468,12 @@ queue_middle_gc_tasks(const General_options& options, } 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 @@ -496,22 +497,22 @@ queue_middle_tasks(const General_options& options, 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); @@ -519,29 +520,29 @@ queue_middle_tasks(const General_options& options, 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 @@ -553,9 +554,9 @@ queue_middle_tasks(const General_options& options, { 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. @@ -564,26 +565,26 @@ queue_middle_tasks(const General_options& options, 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 @@ -676,11 +677,12 @@ queue_middle_tasks(const General_options& options, // 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. @@ -716,12 +718,12 @@ queue_middle_tasks(const General_options& options, || 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; @@ -741,15 +743,15 @@ queue_middle_tasks(const General_options& options, // 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) @@ -761,7 +763,7 @@ queue_middle_tasks(const General_options& options, // 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 @@ -776,7 +778,7 @@ queue_middle_tasks(const General_options& options, workqueue->queue(new Task_function(new Layout_task_runner(options, input_objects, symtab, - target, + target, layout, mapfile), this_blocker, diff --git a/gold/i386.cc b/gold/i386.cc index b4174bc..47f33a0 100644 --- a/gold/i386.cc +++ b/gold/i386.cc @@ -40,6 +40,7 @@ #include "target-select.h" #include "tls.h" #include "freebsd.h" +#include "nacl.h" #include "gc.h" namespace @@ -48,13 +49,17 @@ 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 @@ -90,14 +95,14 @@ class Output_data_plt_i386 : public Output_section_data { 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 @@ -107,43 +112,73 @@ class Output_data_plt_i386 : public Output_section_data 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. @@ -193,6 +228,101 @@ class Output_data_plt_i386 : public Output_section_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 @@ -203,28 +333,28 @@ class Target_i386 : public Sized_target<32, false> 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 @@ -372,6 +502,28 @@ class Target_i386 : public Sized_target<32, false> 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 @@ -398,23 +550,23 @@ class Target_i386 : public Sized_target<32, false> 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); @@ -452,8 +604,8 @@ class Target_i386 : public Sized_target<32, false> // 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 @@ -470,7 +622,7 @@ class Target_i386 : public Sized_target<32, false> // 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, @@ -629,7 +781,7 @@ class Target_i386 : public Sized_target<32, false> // 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) { @@ -697,6 +849,8 @@ const Target::Target_info Target_i386::i386_info = 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 @@ -824,9 +978,11 @@ Target_i386::rel_irelative_section(Layout* layout) // 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_() { @@ -834,11 +990,6 @@ Output_data_plt_i386::Output_data_plt_i386(Layout* layout, 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 @@ -861,7 +1012,7 @@ Output_data_plt_i386::add_entry(Symbol_table* symtab, Layout* layout, 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(); @@ -878,7 +1029,7 @@ Output_data_plt_i386::add_entry(Symbol_table* symtab, Layout* layout, { // 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_; @@ -909,7 +1060,7 @@ Output_data_plt_i386::add_local_ifunc_entry( 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(); @@ -998,7 +1149,7 @@ Output_data_plt_i386::address_for_global(const Symbol* gsym) 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; } @@ -1008,12 +1159,12 @@ Output_data_plt_i386::address_for_global(const Symbol* gsym) 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 @@ -1022,18 +1173,36 @@ const unsigned char Output_data_plt_i386::exec_first_plt_entry[plt_entry_size] = 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 @@ -1043,9 +1212,25 @@ const unsigned char Output_data_plt_i386::exec_plt_entry[plt_entry_size] = 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 @@ -1055,6 +1240,20 @@ const unsigned char Output_data_plt_i386::dyn_plt_entry[plt_entry_size] = 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 @@ -1077,7 +1276,7 @@ Output_data_plt_i386::plt_eh_frame_cie[plt_eh_frame_cie_size] = }; 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. @@ -1130,15 +1329,8 @@ Output_data_plt_i386::do_write(Output_file* of) 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; @@ -1155,40 +1347,29 @@ Output_data_plt_i386::do_write(Output_file* of) 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 @@ -1235,8 +1416,16 @@ Target_i386::make_plt_section(Symbol_table* symtab, Layout* layout) // 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), @@ -1292,7 +1481,7 @@ Target_i386::plt_entry_count() const 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. @@ -1300,7 +1489,7 @@ Target_i386::first_plt_entry_offset() const 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. @@ -1341,7 +1530,7 @@ Target_i386::define_tls_base_symbol(Symbol_table* symtab, Layout* layout) 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) { @@ -1350,7 +1539,7 @@ Target_i386::got_mod_index_entry(Symbol_table* symtab, Layout* layout, 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; } @@ -1505,7 +1694,7 @@ Target_i386::Scan::reloc_needs_plt_for_ifunc( 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; } @@ -1513,14 +1702,14 @@ Target_i386::Scan::reloc_needs_plt_for_ifunc( 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 @@ -1545,13 +1734,13 @@ Target_i386::Scan::local(Symbol_table* symtab, // 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: @@ -1562,15 +1751,15 @@ Target_i386::Scan::local(Symbol_table* symtab, // 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, @@ -1582,8 +1771,8 @@ Target_i386::Scan::local(Symbol_table* symtab, rel_dyn->add_local_section(object, shndx, r_type, output_section, data_shndx, reloc.get_r_offset()); - } - } + } + } break; case elfcpp::R_386_PC32: @@ -1604,9 +1793,9 @@ Target_i386::Scan::local(Symbol_table* symtab, 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 @@ -1616,20 +1805,20 @@ Target_i386::Scan::local(Symbol_table* symtab, 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; @@ -1664,24 +1853,24 @@ Target_i386::Scan::local(Symbol_table* symtab, { 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), @@ -1693,16 +1882,16 @@ Target_i386::Scan::local(Symbol_table* symtab, 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); @@ -1717,9 +1906,9 @@ Target_i386::Scan::local(Symbol_table* symtab, 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: @@ -1728,8 +1917,8 @@ Target_i386::Scan::local(Symbol_table* symtab, 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); @@ -1744,32 +1933,32 @@ Target_i386::Scan::local(Symbol_table* symtab, 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); @@ -1780,15 +1969,15 @@ Target_i386::Scan::local(Symbol_table* symtab, 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; @@ -1837,7 +2026,7 @@ Target_i386::Scan::possible_function_pointer_reloc(unsigned int r_type) case elfcpp::R_386_GOTOFF: case elfcpp::R_386_GOT32: { - return true; + return true; } default: return false; @@ -1879,14 +2068,14 @@ Target_i386::Scan::global_reloc_may_be_function_pointer( 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 @@ -1904,25 +2093,25 @@ Target_i386::Scan::global(Symbol_table* symtab, 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) @@ -1941,21 +2130,21 @@ Target_i386::Scan::global(Symbol_table* symtab, 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; @@ -1963,42 +2152,42 @@ Target_i386::Scan::global(Symbol_table* symtab, 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) @@ -2006,11 +2195,11 @@ Target_i386::Scan::global(Symbol_table* symtab, 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: // @@ -2024,17 +2213,17 @@ Target_i386::Scan::global(Symbol_table* symtab, // // 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. @@ -2050,14 +2239,14 @@ Target_i386::Scan::global(Symbol_table* symtab, && !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; @@ -2070,8 +2259,8 @@ Target_i386::Scan::global(Symbol_table* symtab, // 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; @@ -2113,29 +2302,29 @@ Target_i386::Scan::global(Symbol_table* symtab, { 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); @@ -2143,30 +2332,30 @@ Target_i386::Scan::global(Symbol_table* symtab, 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: @@ -2175,8 +2364,8 @@ Target_i386::Scan::global(Symbol_table* symtab, 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); @@ -2191,29 +2380,29 @@ Target_i386::Scan::global(Symbol_table* symtab, 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); @@ -2224,13 +2413,13 @@ Target_i386::Scan::global(Symbol_table* symtab, 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; @@ -2260,20 +2449,20 @@ Target_i386::Scan::global(Symbol_table* symtab, 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, @@ -2291,16 +2480,16 @@ Target_i386::gc_process_relocs(Symbol_table* symtab, 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) { @@ -2402,8 +2591,8 @@ Target_i386::do_finalize_sections( 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 @@ -2420,8 +2609,8 @@ Target_i386::Relocate::should_apply_static_reloc(const Sized_symbol<32>* gsym, // (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 @@ -2429,8 +2618,8 @@ Target_i386::Relocate::should_apply_static_reloc(const Sized_symbol<32>* gsym, // 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; } @@ -2438,21 +2627,21 @@ Target_i386::Relocate::should_apply_static_reloc(const Sized_symbol<32>* gsym, 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(), @@ -2508,18 +2697,18 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, { 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; @@ -2536,32 +2725,32 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, 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: @@ -2626,7 +2815,7 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, 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: @@ -2653,7 +2842,7 @@ Target_i386::Relocate::relocate(const Relocate_info<32, false>* relinfo, 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, @@ -2691,37 +2880,37 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo, 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); @@ -2731,7 +2920,7 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo, 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 @@ -2739,16 +2928,16 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo, 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) { @@ -2758,19 +2947,19 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo, 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) { @@ -2779,20 +2968,20 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo, 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); @@ -2820,15 +3009,15 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo, 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); @@ -2874,33 +3063,33 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo, 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); @@ -2910,32 +3099,32 @@ Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo, // 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; } } @@ -2965,7 +3154,7 @@ Target_i386::Relocate::tls_gd_to_le(const Relocate_info<32, false>* relinfo, 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; @@ -2975,15 +3164,15 @@ Target_i386::Relocate::tls_gd_to_le(const Relocate_info<32, false>* relinfo, 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); @@ -3027,7 +3216,7 @@ Target_i386::Relocate::tls_gd_to_ie(const Relocate_info<32, false>* relinfo, 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; @@ -3040,24 +3229,24 @@ Target_i386::Relocate::tls_gd_to_ie(const Relocate_info<32, false>* relinfo, 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); } @@ -3091,7 +3280,7 @@ Target_i386::Relocate::tls_desc_gd_to_le( 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); @@ -3103,7 +3292,7 @@ Target_i386::Relocate::tls_desc_gd_to_le( 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; } @@ -3130,7 +3319,7 @@ Target_i386::Relocate::tls_desc_gd_to_ie( 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); } @@ -3141,7 +3330,7 @@ Target_i386::Relocate::tls_desc_gd_to_ie( 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; } @@ -3168,7 +3357,7 @@ Target_i386::Relocate::tls_ld_to_le(const Relocate_info<32, false>* relinfo, // 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); @@ -3218,7 +3407,7 @@ Target_i386::Relocate::tls_ie_to_le(const Relocate_info<32, false>* relinfo, { // 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); } @@ -3226,7 +3415,7 @@ Target_i386::Relocate::tls_ie_to_le(const Relocate_info<32, false>* relinfo, { // 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); } @@ -3245,7 +3434,7 @@ Target_i386::Relocate::tls_ie_to_le(const Relocate_info<32, false>* relinfo, 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 @@ -3471,7 +3660,7 @@ Target_i386::do_code_fill(section_size_type length) const 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. @@ -3481,45 +3670,45 @@ Target_i386::do_code_fill(section_size_type length) const 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, @@ -3563,12 +3752,12 @@ Target_i386::do_is_call_to_non_split(const Symbol* sym, unsigned int) const 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. @@ -3615,7 +3804,8 @@ Target_i386::do_calls_non_split(Relobj* object, unsigned int shndx, *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 { @@ -3631,6 +3821,327 @@ public: { 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. diff --git a/gold/incremental.cc b/gold/incremental.cc index 6436a35..9a61e77 100644 --- a/gold/incremental.cc +++ b/gold/incremental.cc @@ -1,6 +1,6 @@ // 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. @@ -143,7 +143,7 @@ vexplain_no_incremental(const char* format, va_list args) 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); } @@ -296,7 +296,7 @@ Sized_incremental_binary<size, big_endian>::setup_readers() 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 @@ -322,7 +322,7 @@ Sized_incremental_binary<size, big_endian>::setup_readers() 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(); @@ -382,16 +382,16 @@ check_input_args(std::vector<const Input_argument*>& input_args_map, 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; } - } + } } } @@ -421,11 +421,11 @@ Sized_incremental_binary<size, big_endian>::do_check_inputs( 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; } @@ -546,14 +546,14 @@ Sized_incremental_binary<size, big_endian>::do_init_layout(Layout* layout) 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; } @@ -583,7 +583,7 @@ Sized_incremental_binary<size, big_endian>::do_reserve_layout( { 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) { @@ -592,7 +592,7 @@ Sized_incremental_binary<size, big_endian>::do_reserve_layout( 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()); @@ -610,9 +610,9 @@ Sized_incremental_binary<size, big_endian>::do_reserve_layout( 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); @@ -781,7 +781,7 @@ Sized_incremental_binary<size, big_endian>::do_apply_incremental_relocs( // 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(); @@ -803,12 +803,12 @@ Sized_incremental_binary<size, big_endian>::do_apply_incremental_relocs( 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); @@ -818,7 +818,7 @@ Sized_incremental_binary<size, big_endian>::do_apply_incremental_relocs( of->write_output_view(section_offset, view_size, view); } offset = sym_info.next_offset(); - } + } } } @@ -848,15 +848,16 @@ namespace 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; } @@ -893,7 +894,7 @@ open_incremental_binary(Output_file* file) 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; @@ -903,44 +904,44 @@ open_incremental_binary(Output_file* file) 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(); @@ -975,7 +976,7 @@ Incremental_inputs::report_command_line(int argc, const char* const* argv) || 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) @@ -990,20 +991,20 @@ Incremental_inputs::report_command_line(int argc, const char* const* argv) // 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 @@ -1105,7 +1106,7 @@ Incremental_inputs::report_object(Object* obj, unsigned int arg_serial, 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) { @@ -1211,28 +1212,28 @@ Incremental_inputs::create_data_sections(Symbol_table* symtab) #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 @@ -1335,8 +1336,8 @@ Output_section_incremental_inputs<size, big_endian>::set_final_data_size() 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; } @@ -1484,13 +1485,13 @@ Output_section_incremental_inputs<size, big_endian>::write_input_files( { 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); @@ -1628,7 +1629,7 @@ Output_section_incremental_inputs<size, big_endian>::write_info_blocks( // 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()) @@ -1710,8 +1711,8 @@ Output_section_incremental_inputs<size, big_endian>::write_info_blocks( 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 @@ -1911,9 +1912,9 @@ class Global_symbol_visitor_got_plt 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()) @@ -2044,12 +2045,12 @@ Sized_relobj_incr<size, big_endian>::do_layout( 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; @@ -2074,13 +2075,13 @@ Sized_relobj_incr<size, big_endian>::do_layout( { 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); } @@ -2160,7 +2161,7 @@ Sized_relobj_incr<size, big_endian>::do_add_symbols( // 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) @@ -2193,7 +2194,7 @@ Sized_relobj_incr<size, big_endian>::do_add_symbols( 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. @@ -2486,7 +2487,7 @@ Sized_relobj_incr<size, big_endian>::do_count_local_symbols( 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, @@ -2589,7 +2590,7 @@ Sized_relobj_incr<size, big_endian>::do_relocate(const Symbol_table*, 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; @@ -2633,18 +2634,18 @@ Sized_relobj_incr<size, big_endian>::do_relocate(const Symbol_table*, // 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) @@ -2658,7 +2659,7 @@ Sized_relobj_incr<size, big_endian>::do_relocate(const Symbol_table*, { gold_assert(dyn_ov - dyn_oview == dyn_output_size); of->write_output_view(this->local_dynsym_offset_, dyn_output_size, - dyn_oview); + dyn_oview); } } @@ -2768,7 +2769,7 @@ Sized_incr_dynobj<size, big_endian>::do_add_symbols( // 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) { diff --git a/gold/layout.cc b/gold/layout.cc index 65d1432..7155f22 100644 --- a/gold/layout.cc +++ b/gold/layout.cc @@ -1,6 +1,7 @@ // 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. @@ -155,9 +156,9 @@ off_t 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); @@ -222,17 +223,17 @@ void 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. @@ -256,7 +257,7 @@ Layout::Relaxation_debug_check::check_output_data_for_reset_values( ++p) gold_assert((*p)->address_and_file_offset_have_reset_values()); } - + // Save information of SECTIONS for checking later. void @@ -319,7 +320,7 @@ Layout_task_runner::run(Workqueue* workqueue, const Task* task) 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 @@ -349,8 +350,8 @@ Layout_task_runner::run(Workqueue* workqueue, const Task* task) // 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); @@ -579,7 +580,7 @@ Layout::include_section(Sized_relobj_file<size, big_endian>*, const char* name, { // 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() @@ -587,17 +588,17 @@ Layout::include_section(Sized_relobj_file<size, big_endian>*, const char* name, { // 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. @@ -713,27 +714,27 @@ Layout::get_output_section(const char* name, Stringpool::Key name_key, 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) @@ -925,7 +926,7 @@ Layout::init_fixed_output_section(const char* name, 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); @@ -1321,7 +1322,7 @@ Layout::add_to_gdb_index(bool is_type_unit, 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_); @@ -1379,22 +1380,22 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type, 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 { @@ -1497,18 +1498,18 @@ Layout::make_output_section(const char* name, elfcpp::Elf_Word type, // 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; } @@ -1585,12 +1586,12 @@ Layout::default_section_order(Output_section* os, bool is_relro_local) // 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; } @@ -1598,18 +1599,19 @@ Layout::attach_sections_to_segments() // 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); @@ -1649,9 +1651,9 @@ Layout::attach_allocated_section_to_segment(Output_section* os) 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()) @@ -1681,7 +1683,7 @@ Layout::attach_allocated_section_to_segment(Output_section* os) 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); @@ -1695,24 +1697,24 @@ Layout::attach_allocated_section_to_segment(Output_section* os) { // 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 @@ -1883,9 +1885,9 @@ Layout::define_section_symbols(Symbol_table* symtab) { 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 @@ -1951,7 +1953,7 @@ Layout::define_group_signatures(Symbol_table* symtab) // 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(); @@ -1961,11 +1963,13 @@ Layout::find_first_load_seg() 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; @@ -2023,10 +2027,10 @@ Layout::restore_segments(const Segment_states* segment_states) 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; @@ -2059,7 +2063,7 @@ Layout::clean_up_after_relaxation() (*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(); @@ -2073,7 +2077,7 @@ Layout::clean_up_after_relaxation() 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. @@ -2096,7 +2100,7 @@ Layout::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; @@ -2105,7 +2109,7 @@ Layout::prepare_for_relaxation() // 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 @@ -2115,8 +2119,8 @@ Layout::prepare_for_relaxation() // 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. @@ -2148,7 +2152,7 @@ Layout::relaxation_loop_body( 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) @@ -2205,9 +2209,9 @@ Layout::relaxation_loop_body( 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. @@ -2268,11 +2272,11 @@ Layout::find_section_order_index(const std::string& section_name) ++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; } @@ -2290,7 +2294,7 @@ Layout::read_layout_from_file() 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; @@ -2299,17 +2303,17 @@ Layout::read_layout_from_file() 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); } @@ -2373,7 +2377,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab, 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); @@ -2384,7 +2388,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab, 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. @@ -2403,7 +2407,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab, // after we call create_version_sections. this->set_dynamic_symbol_size(symtab); } - + // Create segment headers. Output_segment_headers* segment_headers = (parameters->options().relocatable() @@ -2422,7 +2426,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab, // 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; @@ -2431,7 +2435,7 @@ Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab, // 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 { @@ -2873,8 +2877,8 @@ Layout::create_incremental_info_sections(Symbol_table* symtab) 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); @@ -3054,13 +3058,15 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg, // 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 @@ -3085,15 +3091,39 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg, 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) @@ -3145,16 +3175,37 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg, 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 @@ -3173,7 +3224,7 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg, 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 @@ -3212,7 +3263,7 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg, new_addr = (*p)->set_section_addresses(this, true, addr, &increase_relro, &has_relro, - &off, pshndx); + &off, pshndx); } } @@ -3239,6 +3290,38 @@ Layout::set_segment_offsets(const Target* target, Output_segment* load_seg, } } + 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(); @@ -3326,16 +3409,16 @@ Layout::set_section_offsets(off_t off, Layout::Section_offset_pass pass) } 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()) { @@ -3352,7 +3435,7 @@ Layout::set_section_offsets(off_t off, Layout::Section_offset_pass pass) 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"), @@ -3377,7 +3460,7 @@ Layout::set_section_offsets(off_t off, Layout::Section_offset_pass pass) 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) @@ -3525,7 +3608,7 @@ Layout::create_symtab_sections(const Input_objects* input_objects, ++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; } @@ -3619,7 +3702,7 @@ Layout::create_symtab_sections(const Input_objects* input_objects, 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, @@ -3722,7 +3805,7 @@ Layout::allocated_output_section_count() const 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, @@ -4301,45 +4384,45 @@ Layout::finish_dynamic_section(const Input_objects* input_objects, { 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()) @@ -4351,17 +4434,17 @@ Layout::finish_dynamic_section(const Input_objects* input_objects, 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 { @@ -4370,17 +4453,17 @@ Layout::finish_dynamic_section(const Input_objects* input_objects, // 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) @@ -4652,7 +4735,7 @@ Layout::find_or_add_kept_section(const std::string& name, 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++ @@ -4691,12 +4774,12 @@ Layout::find_or_add_kept_section(const std::string& name, // 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) diff --git a/gold/layout.h b/gold/layout.h index f81ea3b..4643e32 100644 --- a/gold/layout.h +++ b/gold/layout.h @@ -1,6 +1,7 @@ // 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. @@ -171,7 +172,7 @@ class Layout_task_runner : public Task_function_runner 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), @@ -526,7 +527,7 @@ class Layout 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_; } @@ -709,11 +710,11 @@ class Layout { // 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 @@ -736,7 +737,7 @@ class Layout // *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); @@ -903,7 +904,7 @@ class Layout // 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. @@ -982,7 +983,7 @@ class Layout // 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. @@ -1079,7 +1080,7 @@ class Layout // 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 @@ -1087,7 +1088,7 @@ class Layout // 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* @@ -1134,7 +1135,7 @@ class Layout 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; @@ -1205,12 +1206,12 @@ class Layout 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&); @@ -1218,7 +1219,7 @@ class Layout // Verify a section list with recorded information. void verify_sections(const Layout::Section_list&); - + private: // Information we care about a section. struct Section_info diff --git a/gold/nacl.cc b/gold/nacl.cc new file mode 100644 index 0000000..71be4e9 --- /dev/null +++ b/gold/nacl.cc @@ -0,0 +1,46 @@ +// 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 diff --git a/gold/nacl.h b/gold/nacl.h new file mode 100644 index 0000000..bf5853d --- /dev/null +++ b/gold/nacl.h @@ -0,0 +1,243 @@ +// 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) diff --git a/gold/object.cc b/gold/object.cc index 15e5d05..e43ffdc 100644 --- a/gold/object.cc +++ b/gold/object.cc @@ -1,6 +1,7 @@ // 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. @@ -268,28 +269,28 @@ Object::handle_split_stack_section(const char* name) // 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 { @@ -300,9 +301,9 @@ Relobj::copy_symbols_data(Symbols_data* gc_sd, Read_symbols_data* sd, 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 { @@ -318,22 +319,22 @@ Relobj::copy_symbols_data(Symbols_data* gc_sd, Read_symbols_data* sd, 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; } @@ -669,11 +670,11 @@ Sized_relobj_file<size, big_endian>::do_read_symbols(Read_symbols_data* sd) 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_ @@ -874,7 +875,7 @@ Sized_relobj_file<size, big_endian>::include_section_group( } 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 @@ -928,18 +929,18 @@ Sized_relobj_file<size, big_endian>::include_section_group( // 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) @@ -949,11 +950,11 @@ Sized_relobj_file<size, big_endian>::include_section_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()) { @@ -987,8 +988,8 @@ Sized_relobj_file<size, big_endian>::include_section_group( this->set_kept_comdat_section(shndx, kept_object, kept_section->shndx()); } - } - } + } + } } if (relocate_group) @@ -1162,15 +1163,15 @@ Sized_relobj_file<size, big_endian>::layout_eh_frame_section( // 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> @@ -1180,18 +1181,18 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, 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)); @@ -1201,8 +1202,8 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, 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); @@ -1218,7 +1219,7 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, 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; @@ -1233,10 +1234,10 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, 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; } @@ -1245,9 +1246,9 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, 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); @@ -1271,7 +1272,7 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, // 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) @@ -1308,12 +1309,12 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, 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; } @@ -1360,22 +1361,22 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, 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 @@ -1392,23 +1393,23 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, 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. @@ -1424,32 +1425,32 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, 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 @@ -1475,115 +1476,115 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, // 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 @@ -1599,15 +1600,15 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, || 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(); @@ -1631,20 +1632,20 @@ Sized_relobj_file<size, big_endian>::do_layout(Symbol_table* symtab, 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; } @@ -1736,7 +1737,7 @@ Sized_relobj_file<size, big_endian>::do_layout_deferred_sections(Layout* layout) // 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" @@ -1780,7 +1781,7 @@ Sized_relobj_file<size, big_endian>::do_layout_deferred_sections(Layout* layout) if (data_section == NULL) { out_sections[shndx] = NULL; - out_section_offsets[shndx] = invalid_address; + out_section_offsets[shndx] = invalid_address; continue; } @@ -1855,7 +1856,7 @@ Sized_relobj_file<size, big_endian>::do_should_include_member( 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; @@ -1901,7 +1902,7 @@ Sized_relobj_file<size, big_endian>::do_for_all_global_symbols( 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) @@ -2026,16 +2027,16 @@ Sized_relobj_file<size, big_endian>::do_count_local_symbols(Stringpool* pool, 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; } @@ -2052,10 +2053,10 @@ Sized_relobj_file<size, big_endian>::do_count_local_symbols(Stringpool* pool, // 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())) @@ -2089,10 +2090,10 @@ Sized_relobj_file<size, big_endian>::do_count_local_symbols(Stringpool* pool, // 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); @@ -2122,9 +2123,9 @@ Sized_relobj_file<size, big_endian>::compute_final_local_value_internal( 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)) @@ -2146,7 +2147,7 @@ Sized_relobj_file<size, big_endian>::compute_final_local_value_internal( 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)) @@ -2161,7 +2162,7 @@ Sized_relobj_file<size, big_endian>::compute_final_local_value_internal( 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) { @@ -2171,7 +2172,7 @@ Sized_relobj_file<size, big_endian>::compute_final_local_value_internal( secoffset = relaxed_section->address() - os->address(); } } - + if (os == NULL) { // This local symbol belongs to a section we are discarding. @@ -2183,7 +2184,7 @@ Sized_relobj_file<size, big_endian>::compute_final_local_value_internal( 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_) @@ -2336,10 +2337,10 @@ Sized_relobj_file<size, big_endian>::do_set_local_dynsym_indexes( { 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; } @@ -2368,12 +2369,12 @@ Sized_relobj_file<size, big_endian>::do_section_flags(unsigned int shndx) 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 @@ -2387,9 +2388,9 @@ Sized_relobj_file<size, big_endian>::do_section_entsize(unsigned int shndx) 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. @@ -2454,7 +2455,7 @@ Sized_relobj_file<size, big_endian>::write_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()); @@ -2490,38 +2491,38 @@ Sized_relobj_file<size, big_endian>::write_local_symbols( // 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; + } } @@ -2536,7 +2537,7 @@ Sized_relobj_file<size, big_endian>::write_local_symbols( { gold_assert(dyn_ov - dyn_oview == dyn_output_size); of->write_output_view(this->local_dynsym_offset_, dyn_output_size, - dyn_oview); + dyn_oview); } } @@ -2591,26 +2592,26 @@ Sized_relobj_file<size, big_endian>::get_symbol_location_info( && 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; @@ -2738,10 +2739,10 @@ Sized_relobj_file<size, big_endian>::do_discard_decompressed_sections() ++p) { if (p->second.contents != NULL) - { - delete[] p->second.contents; - p->second.contents = NULL; - } + { + delete[] p->second.contents; + p->second.contents = NULL; + } } } @@ -2934,7 +2935,8 @@ make_elf_sized_object(const std::string& name, Input_file* input_file, 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) @@ -2994,7 +2996,7 @@ make_elf_object(const std::string& name, Input_file* input_file, off_t offset, 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; diff --git a/gold/parameters.cc b/gold/parameters.cc index 7fc5730..d69b62c 100644 --- a/gold/parameters.cc +++ b/gold/parameters.cc @@ -1,6 +1,7 @@ // 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. @@ -212,7 +213,7 @@ Parameters::check_target_endianness() 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")); } @@ -352,7 +353,8 @@ parameters_force_valid_target() 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, diff --git a/gold/powerpc.cc b/gold/powerpc.cc index b443304..1bc9dfa 100644 --- a/gold/powerpc.cc +++ b/gold/powerpc.cc @@ -1,6 +1,6 @@ // 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> @@ -62,20 +62,20 @@ class Target_powerpc : public Sized_target<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 @@ -210,21 +210,21 @@ class Target_powerpc : public Sized_target<size, big_endian> 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; } @@ -270,7 +270,7 @@ class Target_powerpc : public Sized_target<size, big_endian> 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*, @@ -330,7 +330,7 @@ class Target_powerpc : public Sized_target<size, big_endian> // 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) { @@ -389,6 +389,8 @@ Target::Target_info Target_powerpc<32, true>::powerpc_info = 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 @@ -413,6 +415,8 @@ Target::Target_info Target_powerpc<32, false>::powerpc_info = 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 @@ -437,6 +441,8 @@ Target::Target_info Target_powerpc<64, true>::powerpc_info = 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 @@ -461,6 +467,8 @@ Target::Target_info Target_powerpc<64, false>::powerpc_info = 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 @@ -952,7 +960,7 @@ static const unsigned int addis_r12_r2 = 0x3d820000; /* addis %r12,%r2,xxx@h 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. @@ -1311,27 +1319,27 @@ Target_powerpc<size, big_endian>::Scan::local( // 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: @@ -1352,8 +1360,8 @@ Target_powerpc<size, big_endian>::Scan::local( 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); @@ -1374,7 +1382,7 @@ Target_powerpc<size, big_endian>::Scan::local( elfcpp::R_POWERPC_RELATIVE, got, off, 0, false); } - } + } else got->add_local(object, r_sym, GOT_TYPE_STANDARD); } @@ -1446,8 +1454,8 @@ Target_powerpc<size, big_endian>::Scan::global( // 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; @@ -1459,38 +1467,38 @@ Target_powerpc<size, big_endian>::Scan::global( 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() @@ -1506,8 +1514,8 @@ Target_powerpc<size, big_endian>::Scan::global( data_shndx, reloc.get_r_offset(), reloc.get_r_addend(), false); - } - } + } + } } break; @@ -1552,31 +1560,31 @@ Target_powerpc<size, big_endian>::Scan::global( 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; @@ -1788,20 +1796,20 @@ Target_powerpc<size, big_endian>::Relocate::relocate( 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) { @@ -2132,7 +2140,8 @@ public: : (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) { @@ -2153,7 +2162,8 @@ public: return this->instantiate_target(); } - Target* do_instantiate_target() + virtual Target* + do_instantiate_target() { return new Target_powerpc<size, big_endian>(); } }; diff --git a/gold/sparc.cc b/gold/sparc.cc index a85bb81..7b78311 100644 --- a/gold/sparc.cc +++ b/gold/sparc.cc @@ -66,20 +66,20 @@ class Target_sparc : public Sized_target<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 @@ -248,24 +248,24 @@ class Target_sparc : public Sized_target<size, big_endian> 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; } @@ -326,7 +326,7 @@ class Target_sparc : public Sized_target<size, big_endian> // 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*, @@ -408,7 +408,7 @@ class Target_sparc : public Sized_target<size, big_endian> // 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) { @@ -473,6 +473,8 @@ Target::Target_info Target_sparc<32, true>::sparc_info = 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 @@ -497,6 +499,8 @@ Target::Target_info Target_sparc<64, true>::sparc_info = 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 @@ -2218,7 +2222,7 @@ Target_sparc<size, big_endian>::Scan::reloc_needs_plt_for_ifunc( 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; } @@ -2265,14 +2269,14 @@ Target_sparc<size, big_endian>::Scan::local( // 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: @@ -2301,26 +2305,26 @@ Target_sparc<size, big_endian>::Scan::local( // 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: @@ -2348,9 +2352,9 @@ Target_sparc<size, big_endian>::Scan::local( 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()); @@ -2397,7 +2401,7 @@ Target_sparc<size, big_endian>::Scan::local( { 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 @@ -2406,11 +2410,11 @@ Target_sparc<size, big_endian>::Scan::local( 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); @@ -2418,7 +2422,7 @@ Target_sparc<size, big_endian>::Scan::local( 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), @@ -2490,11 +2494,11 @@ Target_sparc<size, big_endian>::Scan::local( 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); } @@ -2596,8 +2600,8 @@ Target_sparc<size, big_endian>::Scan::global( // 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; @@ -2665,24 +2669,24 @@ Target_sparc<size, big_endian>::Scan::global( 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: @@ -2711,11 +2715,11 @@ Target_sparc<size, big_endian>::Scan::global( 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 @@ -2737,19 +2741,19 @@ Target_sparc<size, big_endian>::Scan::global( 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() @@ -2765,8 +2769,8 @@ Target_sparc<size, big_endian>::Scan::global( object, data_shndx, reloc.get_r_offset(), reloc.get_r_addend()); - } - } + } + } } break; @@ -2774,8 +2778,8 @@ Target_sparc<size, big_endian>::Scan::global( 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 @@ -2786,11 +2790,11 @@ Target_sparc<size, big_endian>::Scan::global( 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) @@ -2798,10 +2802,10 @@ Target_sparc<size, big_endian>::Scan::global( 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: @@ -2816,10 +2820,10 @@ Target_sparc<size, big_endian>::Scan::global( // // 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 @@ -2838,8 +2842,8 @@ Target_sparc<size, big_endian>::Scan::global( 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); @@ -2854,7 +2858,7 @@ Target_sparc<size, big_endian>::Scan::global( rela_dyn->add_global_relative(gsym, elfcpp::R_SPARC_RELATIVE, got, off, 0, is_ifunc); } - } + } } break; @@ -2881,7 +2885,7 @@ Target_sparc<size, big_endian>::Scan::global( { 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 @@ -2890,11 +2894,11 @@ Target_sparc<size, big_endian>::Scan::global( 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 @@ -2909,10 +2913,10 @@ Target_sparc<size, big_endian>::Scan::global( } 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 : @@ -3235,16 +3239,16 @@ Target_sparc<size, big_endian>::Relocate::relocate( 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: @@ -3268,7 +3272,7 @@ Target_sparc<size, big_endian>::Relocate::relocate( 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 @@ -3282,7 +3286,7 @@ Target_sparc<size, big_endian>::Relocate::relocate( 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 @@ -3435,7 +3439,7 @@ Target_sparc<size, big_endian>::Relocate::relocate( 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 @@ -3649,22 +3653,22 @@ Target_sparc<size, big_endian>::Relocate::relocate_tls( 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; @@ -3729,10 +3733,10 @@ Target_sparc<size, big_endian>::Relocate::relocate_tls( 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: @@ -3759,8 +3763,8 @@ Target_sparc<size, big_endian>::Relocate::relocate_tls( break; } break; - } - } + } + } gold_error_at_location(relinfo, relnum, rela.get_r_offset(), _("unsupported reloc %u"), r_type); @@ -3789,10 +3793,10 @@ Target_sparc<size, big_endian>::Relocate::relocate_tls( 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) @@ -3820,8 +3824,8 @@ Target_sparc<size, big_endian>::Relocate::relocate_tls( } break; } - break; - } + break; + } gold_error_at_location(relinfo, relnum, rela.get_r_offset(), _("unsupported reloc %u"), r_type); @@ -4255,7 +4259,7 @@ Target_sparc<size, big_endian>::do_make_elf_object( 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: @@ -4346,7 +4350,8 @@ public: (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) { @@ -4368,7 +4373,8 @@ public: return this->instantiate_target(); } - Target* do_instantiate_target() + virtual Target* + do_instantiate_target() { return new Target_sparc<size, big_endian>(); } }; diff --git a/gold/target-select.cc b/gold/target-select.cc index 9370a87..e17cb7d 100644 --- a/gold/target-select.cc +++ b/gold/target-select.cc @@ -1,6 +1,7 @@ // 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. @@ -98,8 +99,9 @@ Target_selector::do_target_bfd_name(const Target* target) // 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()) { @@ -108,7 +110,8 @@ select_target(int machine, int size, bool is_big_endian, int osabi, && 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; } diff --git a/gold/target-select.h b/gold/target-select.h index 310c0b9..2e16c2a 100644 --- a/gold/target-select.h +++ b/gold/target-select.h @@ -1,6 +1,7 @@ // 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. @@ -30,6 +31,7 @@ namespace gold { +class Input_file; class Target; class Target_selector; @@ -76,8 +78,9 @@ 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. @@ -160,7 +163,7 @@ class Target_selector // 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 @@ -241,7 +244,8 @@ class Target_selector // 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. diff --git a/gold/target.h b/gold/target.h index b174058..81c8114 100644 --- a/gold/target.h +++ b/gold/target.h @@ -143,6 +143,16 @@ class Target 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 @@ -345,7 +355,7 @@ class Target 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 @@ -365,7 +375,7 @@ class Target { 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. @@ -384,7 +394,7 @@ class Target // 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. @@ -436,6 +446,11 @@ class Target 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; @@ -563,7 +578,7 @@ class Target 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* @@ -620,7 +635,7 @@ class Target 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(); } @@ -789,7 +804,7 @@ class Sized_target : public Target 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 @@ -819,7 +834,7 @@ class Sized_target : public Target 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. diff --git a/gold/testsuite/testfile.cc b/gold/testsuite/testfile.cc index 93e716a..e963d4d 100644 --- a/gold/testsuite/testfile.cc +++ b/gold/testsuite/testfile.cc @@ -1,6 +1,6 @@ // 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. @@ -100,6 +100,8 @@ const Target::Target_info Target_test<size, big_endian>::test_target_info = 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 @@ -154,15 +156,15 @@ class Target_selector_test : public Target_selector : 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) { @@ -198,11 +200,11 @@ class Target_selector_test : public Target_selector return NULL; } - Target* + virtual Target* do_recognize_by_name(const char*) { return NULL; } - void + virtual void do_supported_names(std::vector<const char*>*) { } }; diff --git a/gold/x86_64.cc b/gold/x86_64.cc index d67924b..1339e6f 100644 --- a/gold/x86_64.cc +++ b/gold/x86_64.cc @@ -40,6 +40,7 @@ #include "target-select.h" #include "tls.h" #include "freebsd.h" +#include "nacl.h" #include "gc.h" #include "icf.h" @@ -49,6 +50,9 @@ 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. template<int size> class Output_data_plt_x86_64 : public Output_section_data @@ -56,20 +60,23 @@ 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_() @@ -118,7 +125,10 @@ class Output_data_plt_x86_64 : public Output_section_data // 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* @@ -145,21 +155,21 @@ class Output_data_plt_x86_64 : public Output_section_data { 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. @@ -170,7 +180,74 @@ class Output_data_plt_x86_64 : public Output_section_data 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); @@ -179,27 +256,11 @@ class Output_data_plt_x86_64 : public Output_section_data 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(); @@ -237,6 +298,84 @@ class Output_data_plt_x86_64 : public Output_section_data 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 @@ -252,8 +391,8 @@ class Target_x86_64 : public Sized_target<size, false> // 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), @@ -268,16 +407,16 @@ class Target_x86_64 : public Sized_target<size, false> // 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 @@ -439,7 +578,7 @@ class Target_x86_64 : public Sized_target<size, false> // 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); @@ -477,6 +616,48 @@ class Target_x86_64 : public Sized_target<size, false> 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 @@ -508,22 +689,22 @@ class Target_x86_64 : public Sized_target<size, false> 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 @@ -580,7 +761,7 @@ class Target_x86_64 : public Sized_target<size, false> // 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, @@ -731,7 +912,7 @@ class Target_x86_64 : public Sized_target<size, false> // 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) { @@ -818,6 +999,8 @@ const Target::Target_info Target_x86_64<64>::x86_64_info = 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 @@ -842,6 +1025,8 @@ const Target::Target_info Target_x86_64<32>::x86_64_info = 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 @@ -988,18 +1173,13 @@ Output_data_plt_x86_64<size>::init(Layout* layout) 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. @@ -1040,7 +1220,7 @@ Output_data_plt_x86_64<size>::add_entry(Symbol_table* symtab, Layout* layout, // 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; @@ -1057,7 +1237,8 @@ Output_data_plt_x86_64<size>::add_entry(Symbol_table* symtab, Layout* layout, // 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")); @@ -1065,7 +1246,7 @@ Output_data_plt_x86_64<size>::add_entry(Symbol_table* symtab, Layout* layout, // 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; } @@ -1090,7 +1271,7 @@ Output_data_plt_x86_64<size>::add_local_ifunc_entry( 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(); @@ -1202,7 +1383,7 @@ Output_data_plt_x86_64<size>::address_for_global(const Symbol* gsym) 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; } @@ -1213,7 +1394,7 @@ template<int size> 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. @@ -1224,14 +1405,14 @@ Output_data_plt_x86_64<size>::set_final_data_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 @@ -1241,11 +1422,28 @@ Output_data_plt_x86_64<size>::first_plt_entry[plt_entry_size] = 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 @@ -1256,11 +1454,34 @@ Output_data_plt_x86_64<size>::plt_entry[plt_entry_size] = 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). @@ -1272,10 +1493,32 @@ Output_data_plt_x86_64<size>::tlsdesc_plt_entry[plt_entry_size] = 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. @@ -1296,7 +1539,7 @@ Output_data_plt_x86_64<size>::plt_eh_frame_cie[plt_eh_frame_cie_size] = 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. @@ -1356,15 +1599,8 @@ Output_data_plt_x86_64<size>::do_write(Output_file* of) 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; @@ -1379,47 +1615,35 @@ Output_data_plt_x86_64<size>::do_write(Output_file* of) 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); @@ -1440,9 +1664,13 @@ Target_x86_64<size>::make_plt_section(Symbol_table* symtab, Layout* layout) // 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), @@ -1515,7 +1743,7 @@ template<int size> 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. @@ -1524,7 +1752,7 @@ template<int size> 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. @@ -1581,10 +1809,15 @@ Target_x86_64<size>::init_got_plt_for_update(Symbol_table* symtab, 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); @@ -1758,7 +1991,7 @@ Target_x86_64<size>::define_tls_base_symbol(Symbol_table* symtab, 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); @@ -1788,7 +2021,7 @@ Target_x86_64<size>::got_mod_index_entry(Symbol_table* symtab, Layout* 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; } @@ -1996,10 +2229,10 @@ Target_x86_64<size>::Scan::check_non_pic(Relobj* object, unsigned int r_type, // 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; @@ -2021,7 +2254,7 @@ Target_x86_64<size>::Scan::reloc_needs_plt_for_ifunc( 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; } @@ -2062,15 +2295,15 @@ Target_x86_64<size>::Scan::local(Symbol_table* symtab, // 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: @@ -2082,7 +2315,7 @@ Target_x86_64<size>::Scan::local(Symbol_table* symtab, // 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) { @@ -2096,17 +2329,17 @@ Target_x86_64<size>::Scan::local(Symbol_table* symtab, 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, @@ -2119,8 +2352,8 @@ Target_x86_64<size>::Scan::local(Symbol_table* symtab, r_type, output_section, data_shndx, reloc.get_r_offset(), reloc.get_r_addend()); - } - } + } + } break; case elfcpp::R_X86_64_PC64: @@ -2150,9 +2383,9 @@ Target_x86_64<size>::Scan::local(Symbol_table* symtab, 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 @@ -2162,13 +2395,13 @@ Target_x86_64<size>::Scan::local(Symbol_table* symtab, 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) { @@ -2178,19 +2411,19 @@ Target_x86_64<size>::Scan::local(Symbol_table* symtab, 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; @@ -2219,50 +2452,50 @@ Target_x86_64<size>::Scan::local(Symbol_table* symtab, { 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); @@ -2283,47 +2516,47 @@ Target_x86_64<size>::Scan::local(Symbol_table* symtab, 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; @@ -2369,7 +2602,7 @@ Target_x86_64<size>::Scan::possible_function_pointer_reloc(unsigned int r_type) case elfcpp::R_X86_64_GOTPCREL: case elfcpp::R_X86_64_GOTPLT64: { - return true; + return true; } } return false; @@ -2396,7 +2629,7 @@ Target_x86_64<size>::Scan::local_reloc_may_be_function_pointer( // 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 @@ -2419,10 +2652,10 @@ Target_x86_64<size>::Scan::global_reloc_may_be_function_pointer( // 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. @@ -2430,14 +2663,14 @@ Target_x86_64<size>::Scan::global_reloc_may_be_function_pointer( 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 @@ -2457,25 +2690,25 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab, 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 @@ -2497,25 +2730,25 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab, 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; @@ -2524,26 +2757,26 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab, 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; @@ -2553,9 +2786,9 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab, 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) @@ -2563,11 +2796,11 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab, 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: // @@ -2588,10 +2821,10 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab, && 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. @@ -2607,20 +2840,20 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab, && !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; @@ -2633,8 +2866,8 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab, // 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; @@ -2677,27 +2910,27 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab, { 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); } @@ -2705,30 +2938,30 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab, 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); } @@ -2736,46 +2969,46 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab, 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; @@ -2785,7 +3018,7 @@ Target_x86_64<size>::Scan::global(Symbol_table* symtab, 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; } } @@ -2811,7 +3044,7 @@ Target_x86_64<size>::gc_process_relocs(Symbol_table* symtab, } 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, @@ -2824,7 +3057,7 @@ Target_x86_64<size>::gc_process_relocs(Symbol_table* symtab, needs_special_offset_handling, local_symbol_count, plocal_symbols); - + } // Scan relocations for a section. @@ -2878,7 +3111,7 @@ Target_x86_64<size>::do_finalize_sections( : 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) @@ -2973,7 +3206,7 @@ Target_x86_64<size>::Relocate::relocate( 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) { @@ -3025,17 +3258,17 @@ Target_x86_64<size>::Relocate::relocate( 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; @@ -3056,7 +3289,7 @@ Target_x86_64<size>::Relocate::relocate( case elfcpp::R_X86_64_PC64: Relocate_functions<size, false>::pcrela64(view, object, psymval, addend, - address); + address); break; case elfcpp::R_X86_64_32: @@ -3099,7 +3332,7 @@ Target_x86_64<size>::Relocate::relocate( 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() @@ -3113,9 +3346,9 @@ Target_x86_64<size>::Relocate::relocate( 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, @@ -3129,7 +3362,7 @@ Target_x86_64<size>::Relocate::relocate( 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); @@ -3146,7 +3379,7 @@ Target_x86_64<size>::Relocate::relocate( 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); @@ -3164,19 +3397,19 @@ Target_x86_64<size>::Relocate::relocate( 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; @@ -3204,7 +3437,7 @@ Target_x86_64<size>::Relocate::relocate( 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: @@ -3276,40 +3509,40 @@ Target_x86_64<size>::Relocate::relocate_tls( 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; @@ -3330,16 +3563,16 @@ Target_x86_64<size>::Relocate::relocate_tls( 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) { @@ -3349,45 +3582,45 @@ Target_x86_64<size>::Relocate::relocate_tls( 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; @@ -3399,7 +3632,7 @@ Target_x86_64<size>::Relocate::relocate_tls( optimized_type = tls::TLSOPT_NONE; } if (optimized_type == tls::TLSOPT_TO_LE) - { + { if (tls_segment == NULL) { gold_assert(parameters->errors()->error_count() > 0 @@ -3409,19 +3642,19 @@ Target_x86_64<size>::Relocate::relocate_tls( 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; @@ -3477,29 +3710,29 @@ Target_x86_64<size>::Relocate::relocate_tls( 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); @@ -3545,7 +3778,7 @@ Target_x86_64<size>::Relocate::tls_gd_to_ie( 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) { @@ -3653,7 +3886,7 @@ Target_x86_64<size>::Relocate::tls_desc_gd_to_ie( 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); @@ -3665,7 +3898,7 @@ Target_x86_64<size>::Relocate::tls_desc_gd_to_ie( 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; } @@ -3692,7 +3925,7 @@ Target_x86_64<size>::Relocate::tls_desc_gd_to_le( 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(); @@ -3705,7 +3938,7 @@ Target_x86_64<size>::Relocate::tls_desc_gd_to_le( 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; } @@ -3731,7 +3964,7 @@ Target_x86_64<size>::Relocate::tls_ld_to_le( 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); @@ -3775,7 +4008,7 @@ Target_x86_64<size>::Relocate::tls_ie_to_le( { // movq if (op1 == 0x4c) - view[-3] = 0x49; + view[-3] = 0x49; view[-2] = 0xc7; view[-1] = 0xc0 | reg; } @@ -3783,7 +4016,7 @@ Target_x86_64<size>::Relocate::tls_ie_to_le( { // Special handling for %rsp. if (op1 == 0x4c) - view[-3] = 0x49; + view[-3] = 0x49; view[-2] = 0x81; view[-1] = 0xc0 | reg; } @@ -3791,7 +4024,7 @@ Target_x86_64<size>::Relocate::tls_ie_to_le( { // addq if (op1 == 0x4c) - view[-3] = 0x4d; + view[-3] = 0x4d; view[-2] = 0x8d; view[-1] = 0x80 | reg | (reg << 3); } @@ -4030,7 +4263,7 @@ Target_x86_64<size>::do_code_fill(section_size_type length) const 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. @@ -4038,47 +4271,47 @@ Target_x86_64<size>::do_code_fill(section_size_type length) const 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, @@ -4187,7 +4420,8 @@ Target_x86_64<size>::do_calls_non_split(Relobj* object, unsigned int shndx, *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 @@ -4195,9 +4429,9 @@ 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")) @@ -4209,7 +4443,359 @@ public: }; -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. |