From 54f1b3cf509cd889905287cb8ce6c5ae33911a21 Mon Sep 17 00:00:00 2001 From: Andrew Hsieh Date: Fri, 13 Jun 2014 12:38:00 -0700 Subject: Add upstream binutils-2.25 snapshot 4/4 2014 For MIPS -mmsa support Change-Id: I08c4f002fa7b33dec85ed75956e6ab551bb03c96 --- binutils-2.25/gold/ChangeLog | 15224 +++++++++++++++++++ binutils-2.25/gold/Makefile.am | 363 + binutils-2.25/gold/Makefile.in | 1385 ++ binutils-2.25/gold/NEWS | 11 + binutils-2.25/gold/README | 69 + binutils-2.25/gold/TODO | 26 + binutils-2.25/gold/aclocal.m4 | 992 ++ binutils-2.25/gold/archive.cc | 1313 ++ binutils-2.25/gold/archive.h | 571 + binutils-2.25/gold/arm-reloc-property.cc | 333 + binutils-2.25/gold/arm-reloc-property.h | 386 + binutils-2.25/gold/arm-reloc.def | 194 + binutils-2.25/gold/arm.cc | 12387 +++++++++++++++ binutils-2.25/gold/attributes.cc | 458 + binutils-2.25/gold/attributes.h | 406 + binutils-2.25/gold/binary.cc | 363 + binutils-2.25/gold/binary.h | 116 + binutils-2.25/gold/common.cc | 365 + binutils-2.25/gold/common.h | 67 + binutils-2.25/gold/compressed_output.cc | 247 + binutils-2.25/gold/compressed_output.h | 86 + binutils-2.25/gold/config.in | 277 + binutils-2.25/gold/configure | 9195 +++++++++++ binutils-2.25/gold/configure.ac | 619 + binutils-2.25/gold/configure.tgt | 150 + binutils-2.25/gold/copy-relocs.cc | 258 + binutils-2.25/gold/copy-relocs.h | 156 + binutils-2.25/gold/cref.cc | 407 + binutils-2.25/gold/cref.h | 79 + binutils-2.25/gold/debug.h | 80 + binutils-2.25/gold/defstd.cc | 274 + binutils-2.25/gold/defstd.h | 36 + binutils-2.25/gold/descriptors.cc | 280 + binutils-2.25/gold/descriptors.h | 117 + binutils-2.25/gold/dirsearch.cc | 305 + binutils-2.25/gold/dirsearch.h | 90 + binutils-2.25/gold/dwarf_reader.cc | 2373 +++ binutils-2.25/gold/dwarf_reader.h | 1117 ++ binutils-2.25/gold/dwp.cc | 2224 +++ binutils-2.25/gold/dwp.h | 120 + binutils-2.25/gold/dynobj.cc | 1970 +++ binutils-2.25/gold/dynobj.h | 672 + binutils-2.25/gold/ehframe.cc | 1263 ++ binutils-2.25/gold/ehframe.h | 517 + binutils-2.25/gold/errors.cc | 420 + binutils-2.25/gold/errors.h | 138 + binutils-2.25/gold/expression.cc | 1273 ++ binutils-2.25/gold/ffsll.c | 48 + binutils-2.25/gold/fileread.cc | 1140 ++ binutils-2.25/gold/fileread.h | 611 + binutils-2.25/gold/freebsd.h | 103 + binutils-2.25/gold/ftruncate.c | 111 + binutils-2.25/gold/gc.cc | 74 + binutils-2.25/gold/gc.h | 383 + binutils-2.25/gold/gdb-index.cc | 1343 ++ binutils-2.25/gold/gdb-index.h | 263 + binutils-2.25/gold/gold-threads.cc | 450 + binutils-2.25/gold/gold-threads.h | 267 + binutils-2.25/gold/gold.cc | 888 ++ binutils-2.25/gold/gold.h | 313 + binutils-2.25/gold/i386.cc | 4168 +++++ binutils-2.25/gold/icf.cc | 849 ++ binutils-2.25/gold/icf.h | 179 + binutils-2.25/gold/incremental-dump.cc | 518 + binutils-2.25/gold/incremental.cc | 3123 ++++ binutils-2.25/gold/incremental.h | 2255 +++ binutils-2.25/gold/int_encoding.cc | 134 + binutils-2.25/gold/int_encoding.h | 158 + binutils-2.25/gold/layout.cc | 5909 +++++++ binutils-2.25/gold/layout.h | 1629 ++ binutils-2.25/gold/main.cc | 332 + binutils-2.25/gold/mapfile.cc | 404 + binutils-2.25/gold/mapfile.h | 118 + binutils-2.25/gold/merge.cc | 762 + binutils-2.25/gold/merge.h | 574 + binutils-2.25/gold/mremap.c | 87 + binutils-2.25/gold/nacl.cc | 47 + binutils-2.25/gold/nacl.h | 243 + binutils-2.25/gold/object.cc | 3331 ++++ binutils-2.25/gold/object.h | 2918 ++++ binutils-2.25/gold/options.cc | 1499 ++ binutils-2.25/gold/options.h | 2117 +++ binutils-2.25/gold/output.cc | 5568 +++++++ binutils-2.25/gold/output.h | 4866 ++++++ binutils-2.25/gold/parameters.cc | 389 + binutils-2.25/gold/parameters.h | 246 + binutils-2.25/gold/plugin.cc | 1862 +++ binutils-2.25/gold/plugin.h | 594 + binutils-2.25/gold/po/Make-in | 258 + binutils-2.25/gold/po/POTFILES.in | 102 + binutils-2.25/gold/po/es.po | 2286 +++ binutils-2.25/gold/po/fi.po | 2284 +++ binutils-2.25/gold/po/gold.pot | 2263 +++ binutils-2.25/gold/po/id.po | 1867 +++ binutils-2.25/gold/po/it.po | 2247 +++ binutils-2.25/gold/po/vi.po | 2267 +++ binutils-2.25/gold/powerpc.cc | 7754 ++++++++++ binutils-2.25/gold/pread.c | 42 + binutils-2.25/gold/readsyms.cc | 946 ++ binutils-2.25/gold/readsyms.h | 492 + binutils-2.25/gold/reduced_debug_output.cc | 376 + binutils-2.25/gold/reduced_debug_output.h | 140 + binutils-2.25/gold/reloc-types.h | 92 + binutils-2.25/gold/reloc.cc | 1849 +++ binutils-2.25/gold/reloc.h | 899 ++ binutils-2.25/gold/resolve.cc | 1085 ++ binutils-2.25/gold/script-c.h | 566 + binutils-2.25/gold/script-sections.cc | 4372 ++++++ binutils-2.25/gold/script-sections.h | 337 + binutils-2.25/gold/script.cc | 3409 +++++ binutils-2.25/gold/script.h | 594 + binutils-2.25/gold/sparc.cc | 4395 ++++++ binutils-2.25/gold/stringpool.cc | 529 + binutils-2.25/gold/stringpool.h | 421 + binutils-2.25/gold/symtab.cc | 3657 +++++ binutils-2.25/gold/symtab.h | 1927 +++ binutils-2.25/gold/system.h | 158 + binutils-2.25/gold/target-reloc.h | 835 + binutils-2.25/gold/target-select.cc | 220 + binutils-2.25/gold/target-select.h | 279 + binutils-2.25/gold/target.cc | 260 + binutils-2.25/gold/target.h | 1037 ++ binutils-2.25/gold/testsuite/Makefile.am | 2901 ++++ binutils-2.25/gold/testsuite/Makefile.in | 5892 +++++++ binutils-2.25/gold/testsuite/arm_abs_global.s | 31 + binutils-2.25/gold/testsuite/arm_abs_global.sh | 57 + binutils-2.25/gold/testsuite/arm_abs_lib.s | 37 + binutils-2.25/gold/testsuite/arm_attr_merge.sh | 44 + binutils-2.25/gold/testsuite/arm_attr_merge_6a.s | 4 + binutils-2.25/gold/testsuite/arm_attr_merge_6b.s | 3 + binutils-2.25/gold/testsuite/arm_attr_merge_7a.s | 4 + binutils-2.25/gold/testsuite/arm_attr_merge_7b.s | 4 + binutils-2.25/gold/testsuite/arm_bl_in_range.s | 45 + binutils-2.25/gold/testsuite/arm_bl_out_of_range.s | 46 + .../gold/testsuite/arm_branch_in_range.sh | 73 + .../gold/testsuite/arm_branch_out_of_range.sh | 123 + binutils-2.25/gold/testsuite/arm_branch_range.t | 36 + binutils-2.25/gold/testsuite/arm_cortex_a8.sh | 65 + binutils-2.25/gold/testsuite/arm_cortex_a8_b.s | 30 + .../gold/testsuite/arm_cortex_a8_b_cond.s | 30 + .../gold/testsuite/arm_cortex_a8_b_local.s | 52 + binutils-2.25/gold/testsuite/arm_cortex_a8_bl.s | 30 + binutils-2.25/gold/testsuite/arm_cortex_a8_blx.s | 33 + binutils-2.25/gold/testsuite/arm_cortex_a8_local.s | 29 + .../gold/testsuite/arm_cortex_a8_local_reloc.s | 31 + binutils-2.25/gold/testsuite/arm_exidx_test.s | 31 + binutils-2.25/gold/testsuite/arm_exidx_test.sh | 60 + binutils-2.25/gold/testsuite/arm_farcall_arm_arm.s | 20 + .../gold/testsuite/arm_farcall_arm_arm.sh | 44 + .../gold/testsuite/arm_farcall_arm_thumb.s | 20 + .../gold/testsuite/arm_farcall_arm_thumb.sh | 50 + .../gold/testsuite/arm_farcall_thumb_arm.s | 27 + .../gold/testsuite/arm_farcall_thumb_arm.sh | 56 + .../gold/testsuite/arm_farcall_thumb_thumb.s | 19 + .../gold/testsuite/arm_farcall_thumb_thumb.sh | 74 + binutils-2.25/gold/testsuite/arm_fix_1176.s | 15 + binutils-2.25/gold/testsuite/arm_fix_1176.sh | 61 + binutils-2.25/gold/testsuite/arm_fix_v4bx.s | 15 + binutils-2.25/gold/testsuite/arm_fix_v4bx.sh | 56 + binutils-2.25/gold/testsuite/arm_thm_jump11.s | 57 + binutils-2.25/gold/testsuite/arm_thm_jump11.t | 36 + binutils-2.25/gold/testsuite/arm_thm_jump8.s | 57 + binutils-2.25/gold/testsuite/arm_thm_jump8.t | 36 + binutils-2.25/gold/testsuite/arm_unaligned_reloc.s | 44 + .../gold/testsuite/arm_unaligned_reloc.sh | 57 + binutils-2.25/gold/testsuite/basic_test.cc | 318 + binutils-2.25/gold/testsuite/binary.in | 1 + binutils-2.25/gold/testsuite/binary_test.cc | 46 + binutils-2.25/gold/testsuite/binary_unittest.cc | 184 + binutils-2.25/gold/testsuite/common_test_1.c | 75 + binutils-2.25/gold/testsuite/common_test_1_v1.c | 79 + binutils-2.25/gold/testsuite/common_test_1_v2.c | 77 + binutils-2.25/gold/testsuite/common_test_2.c | 33 + binutils-2.25/gold/testsuite/common_test_3.c | 32 + binutils-2.25/gold/testsuite/constructor_test.cc | 90 + binutils-2.25/gold/testsuite/copy_test.cc | 43 + binutils-2.25/gold/testsuite/copy_test_1.cc | 23 + binutils-2.25/gold/testsuite/copy_test_2.cc | 23 + binutils-2.25/gold/testsuite/copy_test_v1.cc | 47 + binutils-2.25/gold/testsuite/debug_msg.cc | 96 + binutils-2.25/gold/testsuite/debug_msg.sh | 145 + .../testsuite/discard_locals_relocatable_test.c | 52 + binutils-2.25/gold/testsuite/discard_locals_test.c | 40 + .../gold/testsuite/discard_locals_test.sh | 63 + binutils-2.25/gold/testsuite/dwp_test.h | 87 + binutils-2.25/gold/testsuite/dwp_test_1.cc | 210 + binutils-2.25/gold/testsuite/dwp_test_1.s | 2660 ++++ binutils-2.25/gold/testsuite/dwp_test_1.sh | 63 + binutils-2.25/gold/testsuite/dwp_test_1b.cc | 35 + binutils-2.25/gold/testsuite/dwp_test_1b.s | 549 + binutils-2.25/gold/testsuite/dwp_test_2.cc | 144 + binutils-2.25/gold/testsuite/dwp_test_2.s | 1714 +++ binutils-2.25/gold/testsuite/dwp_test_2.sh | 63 + binutils-2.25/gold/testsuite/dwp_test_main.cc | 59 + binutils-2.25/gold/testsuite/dwp_test_main.s | 1399 ++ binutils-2.25/gold/testsuite/dyn_weak_ref.sh | 42 + binutils-2.25/gold/testsuite/dyn_weak_ref_1.c | 39 + binutils-2.25/gold/testsuite/dyn_weak_ref_2.c | 32 + binutils-2.25/gold/testsuite/dynamic_list.sh | 50 + binutils-2.25/gold/testsuite/dynamic_list.t | 11 + binutils-2.25/gold/testsuite/exception_test.h | 27 + binutils-2.25/gold/testsuite/exception_test_1.cc | 52 + binutils-2.25/gold/testsuite/exception_test_2.cc | 31 + .../gold/testsuite/exception_test_main.cc | 35 + binutils-2.25/gold/testsuite/exclude_libs_test.c | 14 + binutils-2.25/gold/testsuite/exclude_libs_test.sh | 63 + binutils-2.25/gold/testsuite/exclude_libs_test_1.c | 32 + binutils-2.25/gold/testsuite/exclude_libs_test_2.c | 24 + binutils-2.25/gold/testsuite/exclude_libs_test_3.c | 24 + binutils-2.25/gold/testsuite/final_layout.cc | 48 + binutils-2.25/gold/testsuite/final_layout.sh | 61 + binutils-2.25/gold/testsuite/gc_comdat_test.sh | 42 + binutils-2.25/gold/testsuite/gc_comdat_test_1.cc | 42 + binutils-2.25/gold/testsuite/gc_comdat_test_2.cc | 35 + .../gold/testsuite/gc_orphan_section_test.cc | 36 + .../gold/testsuite/gc_orphan_section_test.sh | 46 + binutils-2.25/gold/testsuite/gc_tls_test.cc | 32 + binutils-2.25/gold/testsuite/gc_tls_test.sh | 39 + binutils-2.25/gold/testsuite/gdb_index_test.cc | 149 + binutils-2.25/gold/testsuite/gdb_index_test_1.sh | 25 + binutils-2.25/gold/testsuite/gdb_index_test_2.sh | 25 + binutils-2.25/gold/testsuite/gdb_index_test_3.c | 39 + binutils-2.25/gold/testsuite/gdb_index_test_3.sh | 49 + binutils-2.25/gold/testsuite/gdb_index_test_4.sh | 25 + .../gold/testsuite/gdb_index_test_comm.sh | 85 + binutils-2.25/gold/testsuite/hidden_test.sh | 66 + binutils-2.25/gold/testsuite/hidden_test_1.c | 41 + binutils-2.25/gold/testsuite/hidden_test_main.c | 61 + .../gold/testsuite/icf_keep_unique_test.cc | 39 + .../gold/testsuite/icf_keep_unique_test.sh | 39 + .../testsuite/icf_preemptible_functions_test.cc | 47 + .../testsuite/icf_preemptible_functions_test.sh | 37 + binutils-2.25/gold/testsuite/icf_safe_so_test.cc | 74 + binutils-2.25/gold/testsuite/icf_safe_so_test.sh | 102 + binutils-2.25/gold/testsuite/icf_safe_test.cc | 63 + binutils-2.25/gold/testsuite/icf_safe_test.sh | 73 + .../gold/testsuite/icf_sht_rel_addend_test.sh | 37 + .../gold/testsuite/icf_sht_rel_addend_test_1.cc | 44 + .../gold/testsuite/icf_sht_rel_addend_test_2.cc | 39 + .../gold/testsuite/icf_string_merge_test.cc | 50 + .../gold/testsuite/icf_string_merge_test.sh | 39 + binutils-2.25/gold/testsuite/icf_test.cc | 51 + binutils-2.25/gold/testsuite/icf_test.sh | 46 + .../testsuite/icf_virtual_function_folding_test.cc | 71 + binutils-2.25/gold/testsuite/ifunc-sel.h | 92 + binutils-2.25/gold/testsuite/ifuncdep2.c | 50 + binutils-2.25/gold/testsuite/ifuncmain1.c | 64 + binutils-2.25/gold/testsuite/ifuncmain1vis.c | 89 + binutils-2.25/gold/testsuite/ifuncmain2.c | 14 + binutils-2.25/gold/testsuite/ifuncmain3.c | 133 + binutils-2.25/gold/testsuite/ifuncmain4.c | 4 + binutils-2.25/gold/testsuite/ifuncmain5.c | 41 + binutils-2.25/gold/testsuite/ifuncmain6pie.c | 64 + binutils-2.25/gold/testsuite/ifuncmain7.c | 74 + binutils-2.25/gold/testsuite/ifuncmod1.c | 95 + binutils-2.25/gold/testsuite/ifuncmod3.c | 7 + binutils-2.25/gold/testsuite/ifuncmod5.c | 55 + binutils-2.25/gold/testsuite/ifuncmod6.c | 22 + binutils-2.25/gold/testsuite/ifuncvar1.c | 20 + binutils-2.25/gold/testsuite/ifuncvar2.c | 12 + binutils-2.25/gold/testsuite/ifuncvar3.c | 14 + binutils-2.25/gold/testsuite/incr_comdat_test_1.cc | 68 + .../gold/testsuite/incr_comdat_test_2_v1.cc | 44 + .../gold/testsuite/incr_comdat_test_2_v2.cc | 44 + .../gold/testsuite/incr_comdat_test_2_v3.cc | 44 + binutils-2.25/gold/testsuite/incremental_test.sh | 89 + binutils-2.25/gold/testsuite/incremental_test_1.c | 28 + binutils-2.25/gold/testsuite/incremental_test_2.c | 29 + binutils-2.25/gold/testsuite/initpri1.c | 105 + binutils-2.25/gold/testsuite/initpri2.c | 118 + binutils-2.25/gold/testsuite/initpri3.c | 80 + binutils-2.25/gold/testsuite/justsyms.t | 31 + binutils-2.25/gold/testsuite/justsyms_1.cc | 54 + binutils-2.25/gold/testsuite/justsyms_2.cc | 27 + binutils-2.25/gold/testsuite/justsyms_exec.c | 56 + binutils-2.25/gold/testsuite/justsyms_lib.c | 35 + binutils-2.25/gold/testsuite/large.c | 59 + .../gold/testsuite/large_symbol_alignment.cc | 49 + binutils-2.25/gold/testsuite/leb128_unittest.cc | 88 + binutils-2.25/gold/testsuite/many_sections_test.cc | 51 + binutils-2.25/gold/testsuite/memory_test.s | 14 + binutils-2.25/gold/testsuite/memory_test.sh | 57 + binutils-2.25/gold/testsuite/memory_test.t | 26 + .../gold/testsuite/merge_string_literals.sh | 41 + .../gold/testsuite/merge_string_literals_1.cc | 31 + .../gold/testsuite/merge_string_literals_2.cc | 31 + binutils-2.25/gold/testsuite/missing_key_func.cc | 46 + binutils-2.25/gold/testsuite/missing_key_func.sh | 58 + binutils-2.25/gold/testsuite/no_version_test.c | 32 + binutils-2.25/gold/testsuite/no_version_test.sh | 45 + binutils-2.25/gold/testsuite/object_unittest.cc | 105 + binutils-2.25/gold/testsuite/odr_header1.h | 6 + binutils-2.25/gold/testsuite/odr_header2.h | 4 + binutils-2.25/gold/testsuite/odr_violation1.cc | 23 + binutils-2.25/gold/testsuite/odr_violation2.cc | 34 + .../gold/testsuite/plugin_common_test_1.c | 48 + .../gold/testsuite/plugin_common_test_2.c | 45 + .../gold/testsuite/plugin_final_layout.cc | 47 + .../gold/testsuite/plugin_final_layout.sh | 90 + .../gold/testsuite/plugin_section_order.c | 188 + binutils-2.25/gold/testsuite/plugin_test.c | 600 + binutils-2.25/gold/testsuite/plugin_test_1.sh | 59 + binutils-2.25/gold/testsuite/plugin_test_2.sh | 56 + binutils-2.25/gold/testsuite/plugin_test_3.sh | 59 + binutils-2.25/gold/testsuite/plugin_test_4.sh | 58 + binutils-2.25/gold/testsuite/plugin_test_6.sh | 58 + binutils-2.25/gold/testsuite/plugin_test_7.sh | 56 + binutils-2.25/gold/testsuite/plugin_test_7_1.c | 43 + binutils-2.25/gold/testsuite/plugin_test_7_2.c | 33 + binutils-2.25/gold/testsuite/plugin_test_tls.sh | 60 + binutils-2.25/gold/testsuite/pr12826.sh | 44 + binutils-2.25/gold/testsuite/pr12826_1.s | 13 + binutils-2.25/gold/testsuite/pr12826_2.s | 13 + binutils-2.25/gold/testsuite/pr14265.c | 20 + binutils-2.25/gold/testsuite/pr14265.sh | 40 + binutils-2.25/gold/testsuite/pr14265.t | 25 + binutils-2.25/gold/testsuite/protected_1.cc | 58 + binutils-2.25/gold/testsuite/protected_2.cc | 31 + binutils-2.25/gold/testsuite/protected_3.cc | 33 + binutils-2.25/gold/testsuite/protected_4.cc | 32 + binutils-2.25/gold/testsuite/protected_main_1.cc | 40 + binutils-2.25/gold/testsuite/protected_main_2.cc | 29 + binutils-2.25/gold/testsuite/protected_main_3.cc | 31 + binutils-2.25/gold/testsuite/relro_script_test.t | 54 + binutils-2.25/gold/testsuite/relro_test.cc | 160 + binutils-2.25/gold/testsuite/relro_test.sh | 74 + binutils-2.25/gold/testsuite/relro_test_main.cc | 33 + .../gold/testsuite/retain_symbols_file_test.sh | 54 + binutils-2.25/gold/testsuite/script_test_1.cc | 47 + binutils-2.25/gold/testsuite/script_test_1.t | 29 + binutils-2.25/gold/testsuite/script_test_10.s | 14 + binutils-2.25/gold/testsuite/script_test_10.sh | 46 + binutils-2.25/gold/testsuite/script_test_10.t | 34 + binutils-2.25/gold/testsuite/script_test_11.c | 16 + binutils-2.25/gold/testsuite/script_test_11.t | 8 + binutils-2.25/gold/testsuite/script_test_2.cc | 74 + binutils-2.25/gold/testsuite/script_test_2.t | 69 + binutils-2.25/gold/testsuite/script_test_2a.cc | 24 + binutils-2.25/gold/testsuite/script_test_2b.cc | 24 + binutils-2.25/gold/testsuite/script_test_3.sh | 102 + binutils-2.25/gold/testsuite/script_test_3.t | 55 + binutils-2.25/gold/testsuite/script_test_4.sh | 41 + binutils-2.25/gold/testsuite/script_test_4.t | 45 + binutils-2.25/gold/testsuite/script_test_5.cc | 45 + binutils-2.25/gold/testsuite/script_test_5.sh | 43 + binutils-2.25/gold/testsuite/script_test_5.t | 44 + binutils-2.25/gold/testsuite/script_test_6.sh | 43 + binutils-2.25/gold/testsuite/script_test_6.t | 45 + binutils-2.25/gold/testsuite/script_test_7.sh | 43 + binutils-2.25/gold/testsuite/script_test_7.t | 45 + binutils-2.25/gold/testsuite/script_test_8.sh | 44 + binutils-2.25/gold/testsuite/script_test_9.cc | 29 + binutils-2.25/gold/testsuite/script_test_9.sh | 42 + binutils-2.25/gold/testsuite/script_test_9.t | 28 + binutils-2.25/gold/testsuite/searched_file_test.cc | 36 + .../gold/testsuite/searched_file_test_lib.cc | 27 + .../gold/testsuite/section_sorting_name.cc | 59 + .../gold/testsuite/section_sorting_name.sh | 66 + binutils-2.25/gold/testsuite/split_i386.sh | 54 + binutils-2.25/gold/testsuite/split_i386_1.s | 33 + binutils-2.25/gold/testsuite/split_i386_2.s | 33 + binutils-2.25/gold/testsuite/split_i386_3.s | 22 + binutils-2.25/gold/testsuite/split_i386_4.s | 23 + binutils-2.25/gold/testsuite/split_i386_n.s | 12 + binutils-2.25/gold/testsuite/split_x86_64.sh | 54 + binutils-2.25/gold/testsuite/split_x86_64_1.s | 33 + binutils-2.25/gold/testsuite/split_x86_64_2.s | 33 + binutils-2.25/gold/testsuite/split_x86_64_3.s | 22 + binutils-2.25/gold/testsuite/split_x86_64_4.s | 23 + binutils-2.25/gold/testsuite/split_x86_64_n.s | 12 + binutils-2.25/gold/testsuite/start_lib_test_1.c | 32 + binutils-2.25/gold/testsuite/start_lib_test_2.c | 30 + binutils-2.25/gold/testsuite/start_lib_test_3.c | 25 + binutils-2.25/gold/testsuite/start_lib_test_main.c | 33 + .../gold/testsuite/strong_ref_weak_def.sh | 42 + .../gold/testsuite/strong_ref_weak_def_1.c | 39 + .../gold/testsuite/strong_ref_weak_def_2.c | 37 + binutils-2.25/gold/testsuite/test.cc | 107 + binutils-2.25/gold/testsuite/test.h | 145 + binutils-2.25/gold/testsuite/testfile.cc | 949 ++ binutils-2.25/gold/testsuite/testfile.h | 49 + binutils-2.25/gold/testsuite/testmain.cc | 40 + .../gold/testsuite/text_section_grouping.cc | 72 + .../gold/testsuite/text_section_grouping.sh | 73 + binutils-2.25/gold/testsuite/thin_archive_main.cc | 39 + .../gold/testsuite/thin_archive_test_1.cc | 37 + .../gold/testsuite/thin_archive_test_2.cc | 37 + .../gold/testsuite/thin_archive_test_3.cc | 37 + .../gold/testsuite/thin_archive_test_4.cc | 35 + binutils-2.25/gold/testsuite/thumb2_branch_range.t | 36 + binutils-2.25/gold/testsuite/thumb_bl_in_range.s | 56 + .../gold/testsuite/thumb_bl_out_of_range.s | 62 + .../gold/testsuite/thumb_bl_out_of_range_local.s | 61 + binutils-2.25/gold/testsuite/thumb_blx_in_range.s | 64 + .../gold/testsuite/thumb_blx_out_of_range.s | 66 + binutils-2.25/gold/testsuite/thumb_branch_range.t | 36 + binutils-2.25/gold/testsuite/tls_test.cc | 224 + binutils-2.25/gold/testsuite/tls_test.h | 56 + binutils-2.25/gold/testsuite/tls_test_c.c | 65 + binutils-2.25/gold/testsuite/tls_test_file2.cc | 30 + binutils-2.25/gold/testsuite/tls_test_main.cc | 173 + binutils-2.25/gold/testsuite/two_file_shared.sh | 30 + binutils-2.25/gold/testsuite/two_file_test.h | 78 + binutils-2.25/gold/testsuite/two_file_test_1.cc | 238 + binutils-2.25/gold/testsuite/two_file_test_1_v1.cc | 236 + binutils-2.25/gold/testsuite/two_file_test_1b.cc | 41 + .../gold/testsuite/two_file_test_1b_v1.cc | 46 + binutils-2.25/gold/testsuite/two_file_test_2.cc | 145 + .../gold/testsuite/two_file_test_2_tls.cc | 147 + binutils-2.25/gold/testsuite/two_file_test_2_v1.cc | 150 + binutils-2.25/gold/testsuite/two_file_test_main.cc | 57 + binutils-2.25/gold/testsuite/two_file_test_tls.cc | 60 + binutils-2.25/gold/testsuite/undef_symbol.cc | 40 + binutils-2.25/gold/testsuite/undef_symbol.sh | 45 + binutils-2.25/gold/testsuite/undef_symbol_main.cc | 29 + binutils-2.25/gold/testsuite/ver_matching_def.cc | 73 + binutils-2.25/gold/testsuite/ver_matching_test.sh | 88 + binutils-2.25/gold/testsuite/ver_test.h | 43 + binutils-2.25/gold/testsuite/ver_test_1.cc | 33 + binutils-2.25/gold/testsuite/ver_test_1.sh | 30 + binutils-2.25/gold/testsuite/ver_test_10.script | 30 + binutils-2.25/gold/testsuite/ver_test_10.sh | 44 + binutils-2.25/gold/testsuite/ver_test_2.cc | 40 + binutils-2.25/gold/testsuite/ver_test_2.script | 31 + binutils-2.25/gold/testsuite/ver_test_2.sh | 45 + binutils-2.25/gold/testsuite/ver_test_3.cc | 33 + binutils-2.25/gold/testsuite/ver_test_4.cc | 64 + binutils-2.25/gold/testsuite/ver_test_4.script | 35 + binutils-2.25/gold/testsuite/ver_test_4.sh | 44 + binutils-2.25/gold/testsuite/ver_test_5.cc | 29 + binutils-2.25/gold/testsuite/ver_test_5.script | 31 + binutils-2.25/gold/testsuite/ver_test_5.sh | 44 + binutils-2.25/gold/testsuite/ver_test_6.c | 35 + binutils-2.25/gold/testsuite/ver_test_7.cc | 37 + binutils-2.25/gold/testsuite/ver_test_7.sh | 44 + binutils-2.25/gold/testsuite/ver_test_8.script | 26 + binutils-2.25/gold/testsuite/ver_test_9.cc | 50 + binutils-2.25/gold/testsuite/ver_test_main.cc | 74 + binutils-2.25/gold/testsuite/ver_test_main_2.cc | 32 + binutils-2.25/gold/testsuite/version_script.map | 34 + .../gold/testsuite/weak_alias_test.script | 8 + binutils-2.25/gold/testsuite/weak_alias_test_1.cc | 52 + binutils-2.25/gold/testsuite/weak_alias_test_2.cc | 41 + binutils-2.25/gold/testsuite/weak_alias_test_3.cc | 26 + binutils-2.25/gold/testsuite/weak_alias_test_4.cc | 68 + binutils-2.25/gold/testsuite/weak_alias_test_5.cc | 39 + .../gold/testsuite/weak_alias_test_main.cc | 80 + binutils-2.25/gold/testsuite/weak_plt.sh | 28 + binutils-2.25/gold/testsuite/weak_plt_main.cc | 33 + binutils-2.25/gold/testsuite/weak_plt_shared.cc | 29 + binutils-2.25/gold/testsuite/weak_test.cc | 47 + binutils-2.25/gold/testsuite/weak_undef.h | 25 + binutils-2.25/gold/testsuite/weak_undef_file1.cc | 75 + binutils-2.25/gold/testsuite/weak_undef_file2.cc | 70 + binutils-2.25/gold/testsuite/weak_undef_test.cc | 106 + binutils-2.25/gold/tilegx.cc | 4924 ++++++ binutils-2.25/gold/timer.cc | 133 + binutils-2.25/gold/timer.h | 80 + binutils-2.25/gold/tls.h | 81 + binutils-2.25/gold/token.h | 335 + binutils-2.25/gold/version.cc | 82 + binutils-2.25/gold/workqueue-internal.h | 109 + binutils-2.25/gold/workqueue-threads.cc | 199 + binutils-2.25/gold/workqueue.cc | 521 + binutils-2.25/gold/workqueue.h | 295 + binutils-2.25/gold/x86_64.cc | 4836 ++++++ binutils-2.25/gold/yyscript.y | 1133 ++ 467 files changed, 207108 insertions(+) create mode 100644 binutils-2.25/gold/ChangeLog create mode 100644 binutils-2.25/gold/Makefile.am create mode 100644 binutils-2.25/gold/Makefile.in create mode 100644 binutils-2.25/gold/NEWS create mode 100644 binutils-2.25/gold/README create mode 100644 binutils-2.25/gold/TODO create mode 100644 binutils-2.25/gold/aclocal.m4 create mode 100644 binutils-2.25/gold/archive.cc create mode 100644 binutils-2.25/gold/archive.h create mode 100644 binutils-2.25/gold/arm-reloc-property.cc create mode 100644 binutils-2.25/gold/arm-reloc-property.h create mode 100644 binutils-2.25/gold/arm-reloc.def create mode 100644 binutils-2.25/gold/arm.cc create mode 100644 binutils-2.25/gold/attributes.cc create mode 100644 binutils-2.25/gold/attributes.h create mode 100644 binutils-2.25/gold/binary.cc create mode 100644 binutils-2.25/gold/binary.h create mode 100644 binutils-2.25/gold/common.cc create mode 100644 binutils-2.25/gold/common.h create mode 100644 binutils-2.25/gold/compressed_output.cc create mode 100644 binutils-2.25/gold/compressed_output.h create mode 100644 binutils-2.25/gold/config.in create mode 100755 binutils-2.25/gold/configure create mode 100644 binutils-2.25/gold/configure.ac create mode 100644 binutils-2.25/gold/configure.tgt create mode 100644 binutils-2.25/gold/copy-relocs.cc create mode 100644 binutils-2.25/gold/copy-relocs.h create mode 100644 binutils-2.25/gold/cref.cc create mode 100644 binutils-2.25/gold/cref.h create mode 100644 binutils-2.25/gold/debug.h create mode 100644 binutils-2.25/gold/defstd.cc create mode 100644 binutils-2.25/gold/defstd.h create mode 100644 binutils-2.25/gold/descriptors.cc create mode 100644 binutils-2.25/gold/descriptors.h create mode 100644 binutils-2.25/gold/dirsearch.cc create mode 100644 binutils-2.25/gold/dirsearch.h create mode 100644 binutils-2.25/gold/dwarf_reader.cc create mode 100644 binutils-2.25/gold/dwarf_reader.h create mode 100644 binutils-2.25/gold/dwp.cc create mode 100644 binutils-2.25/gold/dwp.h create mode 100644 binutils-2.25/gold/dynobj.cc create mode 100644 binutils-2.25/gold/dynobj.h create mode 100644 binutils-2.25/gold/ehframe.cc create mode 100644 binutils-2.25/gold/ehframe.h create mode 100644 binutils-2.25/gold/errors.cc create mode 100644 binutils-2.25/gold/errors.h create mode 100644 binutils-2.25/gold/expression.cc create mode 100644 binutils-2.25/gold/ffsll.c create mode 100644 binutils-2.25/gold/fileread.cc create mode 100644 binutils-2.25/gold/fileread.h create mode 100644 binutils-2.25/gold/freebsd.h create mode 100644 binutils-2.25/gold/ftruncate.c create mode 100644 binutils-2.25/gold/gc.cc create mode 100644 binutils-2.25/gold/gc.h create mode 100644 binutils-2.25/gold/gdb-index.cc create mode 100644 binutils-2.25/gold/gdb-index.h create mode 100644 binutils-2.25/gold/gold-threads.cc create mode 100644 binutils-2.25/gold/gold-threads.h create mode 100644 binutils-2.25/gold/gold.cc create mode 100644 binutils-2.25/gold/gold.h create mode 100644 binutils-2.25/gold/i386.cc create mode 100644 binutils-2.25/gold/icf.cc create mode 100644 binutils-2.25/gold/icf.h create mode 100644 binutils-2.25/gold/incremental-dump.cc create mode 100644 binutils-2.25/gold/incremental.cc create mode 100644 binutils-2.25/gold/incremental.h create mode 100644 binutils-2.25/gold/int_encoding.cc create mode 100644 binutils-2.25/gold/int_encoding.h create mode 100644 binutils-2.25/gold/layout.cc create mode 100644 binutils-2.25/gold/layout.h create mode 100644 binutils-2.25/gold/main.cc create mode 100644 binutils-2.25/gold/mapfile.cc create mode 100644 binutils-2.25/gold/mapfile.h create mode 100644 binutils-2.25/gold/merge.cc create mode 100644 binutils-2.25/gold/merge.h create mode 100644 binutils-2.25/gold/mremap.c create mode 100644 binutils-2.25/gold/nacl.cc create mode 100644 binutils-2.25/gold/nacl.h create mode 100644 binutils-2.25/gold/object.cc create mode 100644 binutils-2.25/gold/object.h create mode 100644 binutils-2.25/gold/options.cc create mode 100644 binutils-2.25/gold/options.h create mode 100644 binutils-2.25/gold/output.cc create mode 100644 binutils-2.25/gold/output.h create mode 100644 binutils-2.25/gold/parameters.cc create mode 100644 binutils-2.25/gold/parameters.h create mode 100644 binutils-2.25/gold/plugin.cc create mode 100644 binutils-2.25/gold/plugin.h create mode 100644 binutils-2.25/gold/po/Make-in create mode 100644 binutils-2.25/gold/po/POTFILES.in create mode 100644 binutils-2.25/gold/po/es.po create mode 100644 binutils-2.25/gold/po/fi.po create mode 100644 binutils-2.25/gold/po/gold.pot create mode 100644 binutils-2.25/gold/po/id.po create mode 100644 binutils-2.25/gold/po/it.po create mode 100644 binutils-2.25/gold/po/vi.po create mode 100644 binutils-2.25/gold/powerpc.cc create mode 100644 binutils-2.25/gold/pread.c create mode 100644 binutils-2.25/gold/readsyms.cc create mode 100644 binutils-2.25/gold/readsyms.h create mode 100644 binutils-2.25/gold/reduced_debug_output.cc create mode 100644 binutils-2.25/gold/reduced_debug_output.h create mode 100644 binutils-2.25/gold/reloc-types.h create mode 100644 binutils-2.25/gold/reloc.cc create mode 100644 binutils-2.25/gold/reloc.h create mode 100644 binutils-2.25/gold/resolve.cc create mode 100644 binutils-2.25/gold/script-c.h create mode 100644 binutils-2.25/gold/script-sections.cc create mode 100644 binutils-2.25/gold/script-sections.h create mode 100644 binutils-2.25/gold/script.cc create mode 100644 binutils-2.25/gold/script.h create mode 100644 binutils-2.25/gold/sparc.cc create mode 100644 binutils-2.25/gold/stringpool.cc create mode 100644 binutils-2.25/gold/stringpool.h create mode 100644 binutils-2.25/gold/symtab.cc create mode 100644 binutils-2.25/gold/symtab.h create mode 100644 binutils-2.25/gold/system.h create mode 100644 binutils-2.25/gold/target-reloc.h create mode 100644 binutils-2.25/gold/target-select.cc create mode 100644 binutils-2.25/gold/target-select.h create mode 100644 binutils-2.25/gold/target.cc create mode 100644 binutils-2.25/gold/target.h create mode 100644 binutils-2.25/gold/testsuite/Makefile.am create mode 100644 binutils-2.25/gold/testsuite/Makefile.in create mode 100644 binutils-2.25/gold/testsuite/arm_abs_global.s create mode 100755 binutils-2.25/gold/testsuite/arm_abs_global.sh create mode 100644 binutils-2.25/gold/testsuite/arm_abs_lib.s create mode 100755 binutils-2.25/gold/testsuite/arm_attr_merge.sh create mode 100644 binutils-2.25/gold/testsuite/arm_attr_merge_6a.s create mode 100644 binutils-2.25/gold/testsuite/arm_attr_merge_6b.s create mode 100644 binutils-2.25/gold/testsuite/arm_attr_merge_7a.s create mode 100644 binutils-2.25/gold/testsuite/arm_attr_merge_7b.s create mode 100644 binutils-2.25/gold/testsuite/arm_bl_in_range.s create mode 100644 binutils-2.25/gold/testsuite/arm_bl_out_of_range.s create mode 100755 binutils-2.25/gold/testsuite/arm_branch_in_range.sh create mode 100755 binutils-2.25/gold/testsuite/arm_branch_out_of_range.sh create mode 100644 binutils-2.25/gold/testsuite/arm_branch_range.t create mode 100755 binutils-2.25/gold/testsuite/arm_cortex_a8.sh create mode 100644 binutils-2.25/gold/testsuite/arm_cortex_a8_b.s create mode 100644 binutils-2.25/gold/testsuite/arm_cortex_a8_b_cond.s create mode 100644 binutils-2.25/gold/testsuite/arm_cortex_a8_b_local.s create mode 100644 binutils-2.25/gold/testsuite/arm_cortex_a8_bl.s create mode 100644 binutils-2.25/gold/testsuite/arm_cortex_a8_blx.s create mode 100644 binutils-2.25/gold/testsuite/arm_cortex_a8_local.s create mode 100644 binutils-2.25/gold/testsuite/arm_cortex_a8_local_reloc.s create mode 100644 binutils-2.25/gold/testsuite/arm_exidx_test.s create mode 100755 binutils-2.25/gold/testsuite/arm_exidx_test.sh create mode 100644 binutils-2.25/gold/testsuite/arm_farcall_arm_arm.s create mode 100755 binutils-2.25/gold/testsuite/arm_farcall_arm_arm.sh create mode 100644 binutils-2.25/gold/testsuite/arm_farcall_arm_thumb.s create mode 100755 binutils-2.25/gold/testsuite/arm_farcall_arm_thumb.sh create mode 100644 binutils-2.25/gold/testsuite/arm_farcall_thumb_arm.s create mode 100755 binutils-2.25/gold/testsuite/arm_farcall_thumb_arm.sh create mode 100644 binutils-2.25/gold/testsuite/arm_farcall_thumb_thumb.s create mode 100755 binutils-2.25/gold/testsuite/arm_farcall_thumb_thumb.sh create mode 100644 binutils-2.25/gold/testsuite/arm_fix_1176.s create mode 100755 binutils-2.25/gold/testsuite/arm_fix_1176.sh create mode 100644 binutils-2.25/gold/testsuite/arm_fix_v4bx.s create mode 100755 binutils-2.25/gold/testsuite/arm_fix_v4bx.sh create mode 100644 binutils-2.25/gold/testsuite/arm_thm_jump11.s create mode 100644 binutils-2.25/gold/testsuite/arm_thm_jump11.t create mode 100644 binutils-2.25/gold/testsuite/arm_thm_jump8.s create mode 100644 binutils-2.25/gold/testsuite/arm_thm_jump8.t create mode 100644 binutils-2.25/gold/testsuite/arm_unaligned_reloc.s create mode 100755 binutils-2.25/gold/testsuite/arm_unaligned_reloc.sh create mode 100644 binutils-2.25/gold/testsuite/basic_test.cc create mode 100644 binutils-2.25/gold/testsuite/binary.in create mode 100644 binutils-2.25/gold/testsuite/binary_test.cc create mode 100644 binutils-2.25/gold/testsuite/binary_unittest.cc create mode 100644 binutils-2.25/gold/testsuite/common_test_1.c create mode 100644 binutils-2.25/gold/testsuite/common_test_1_v1.c create mode 100644 binutils-2.25/gold/testsuite/common_test_1_v2.c create mode 100644 binutils-2.25/gold/testsuite/common_test_2.c create mode 100644 binutils-2.25/gold/testsuite/common_test_3.c create mode 100644 binutils-2.25/gold/testsuite/constructor_test.cc create mode 100644 binutils-2.25/gold/testsuite/copy_test.cc create mode 100644 binutils-2.25/gold/testsuite/copy_test_1.cc create mode 100644 binutils-2.25/gold/testsuite/copy_test_2.cc create mode 100644 binutils-2.25/gold/testsuite/copy_test_v1.cc create mode 100644 binutils-2.25/gold/testsuite/debug_msg.cc create mode 100755 binutils-2.25/gold/testsuite/debug_msg.sh create mode 100644 binutils-2.25/gold/testsuite/discard_locals_relocatable_test.c create mode 100644 binutils-2.25/gold/testsuite/discard_locals_test.c create mode 100755 binutils-2.25/gold/testsuite/discard_locals_test.sh create mode 100644 binutils-2.25/gold/testsuite/dwp_test.h create mode 100644 binutils-2.25/gold/testsuite/dwp_test_1.cc create mode 100644 binutils-2.25/gold/testsuite/dwp_test_1.s create mode 100755 binutils-2.25/gold/testsuite/dwp_test_1.sh create mode 100644 binutils-2.25/gold/testsuite/dwp_test_1b.cc create mode 100644 binutils-2.25/gold/testsuite/dwp_test_1b.s create mode 100644 binutils-2.25/gold/testsuite/dwp_test_2.cc create mode 100644 binutils-2.25/gold/testsuite/dwp_test_2.s create mode 100755 binutils-2.25/gold/testsuite/dwp_test_2.sh create mode 100644 binutils-2.25/gold/testsuite/dwp_test_main.cc create mode 100644 binutils-2.25/gold/testsuite/dwp_test_main.s create mode 100755 binutils-2.25/gold/testsuite/dyn_weak_ref.sh create mode 100644 binutils-2.25/gold/testsuite/dyn_weak_ref_1.c create mode 100644 binutils-2.25/gold/testsuite/dyn_weak_ref_2.c create mode 100755 binutils-2.25/gold/testsuite/dynamic_list.sh create mode 100644 binutils-2.25/gold/testsuite/dynamic_list.t create mode 100644 binutils-2.25/gold/testsuite/exception_test.h create mode 100644 binutils-2.25/gold/testsuite/exception_test_1.cc create mode 100644 binutils-2.25/gold/testsuite/exception_test_2.cc create mode 100644 binutils-2.25/gold/testsuite/exception_test_main.cc create mode 100644 binutils-2.25/gold/testsuite/exclude_libs_test.c create mode 100755 binutils-2.25/gold/testsuite/exclude_libs_test.sh create mode 100644 binutils-2.25/gold/testsuite/exclude_libs_test_1.c create mode 100644 binutils-2.25/gold/testsuite/exclude_libs_test_2.c create mode 100644 binutils-2.25/gold/testsuite/exclude_libs_test_3.c create mode 100644 binutils-2.25/gold/testsuite/final_layout.cc create mode 100755 binutils-2.25/gold/testsuite/final_layout.sh create mode 100755 binutils-2.25/gold/testsuite/gc_comdat_test.sh create mode 100644 binutils-2.25/gold/testsuite/gc_comdat_test_1.cc create mode 100644 binutils-2.25/gold/testsuite/gc_comdat_test_2.cc create mode 100644 binutils-2.25/gold/testsuite/gc_orphan_section_test.cc create mode 100755 binutils-2.25/gold/testsuite/gc_orphan_section_test.sh create mode 100644 binutils-2.25/gold/testsuite/gc_tls_test.cc create mode 100755 binutils-2.25/gold/testsuite/gc_tls_test.sh create mode 100644 binutils-2.25/gold/testsuite/gdb_index_test.cc create mode 100755 binutils-2.25/gold/testsuite/gdb_index_test_1.sh create mode 100755 binutils-2.25/gold/testsuite/gdb_index_test_2.sh create mode 100644 binutils-2.25/gold/testsuite/gdb_index_test_3.c create mode 100755 binutils-2.25/gold/testsuite/gdb_index_test_3.sh create mode 100755 binutils-2.25/gold/testsuite/gdb_index_test_4.sh create mode 100755 binutils-2.25/gold/testsuite/gdb_index_test_comm.sh create mode 100755 binutils-2.25/gold/testsuite/hidden_test.sh create mode 100644 binutils-2.25/gold/testsuite/hidden_test_1.c create mode 100644 binutils-2.25/gold/testsuite/hidden_test_main.c create mode 100644 binutils-2.25/gold/testsuite/icf_keep_unique_test.cc create mode 100755 binutils-2.25/gold/testsuite/icf_keep_unique_test.sh create mode 100644 binutils-2.25/gold/testsuite/icf_preemptible_functions_test.cc create mode 100755 binutils-2.25/gold/testsuite/icf_preemptible_functions_test.sh create mode 100644 binutils-2.25/gold/testsuite/icf_safe_so_test.cc create mode 100755 binutils-2.25/gold/testsuite/icf_safe_so_test.sh create mode 100644 binutils-2.25/gold/testsuite/icf_safe_test.cc create mode 100755 binutils-2.25/gold/testsuite/icf_safe_test.sh create mode 100755 binutils-2.25/gold/testsuite/icf_sht_rel_addend_test.sh create mode 100644 binutils-2.25/gold/testsuite/icf_sht_rel_addend_test_1.cc create mode 100644 binutils-2.25/gold/testsuite/icf_sht_rel_addend_test_2.cc create mode 100644 binutils-2.25/gold/testsuite/icf_string_merge_test.cc create mode 100755 binutils-2.25/gold/testsuite/icf_string_merge_test.sh create mode 100644 binutils-2.25/gold/testsuite/icf_test.cc create mode 100755 binutils-2.25/gold/testsuite/icf_test.sh create mode 100644 binutils-2.25/gold/testsuite/icf_virtual_function_folding_test.cc create mode 100644 binutils-2.25/gold/testsuite/ifunc-sel.h create mode 100644 binutils-2.25/gold/testsuite/ifuncdep2.c create mode 100644 binutils-2.25/gold/testsuite/ifuncmain1.c create mode 100644 binutils-2.25/gold/testsuite/ifuncmain1vis.c create mode 100644 binutils-2.25/gold/testsuite/ifuncmain2.c create mode 100644 binutils-2.25/gold/testsuite/ifuncmain3.c create mode 100644 binutils-2.25/gold/testsuite/ifuncmain4.c create mode 100644 binutils-2.25/gold/testsuite/ifuncmain5.c create mode 100644 binutils-2.25/gold/testsuite/ifuncmain6pie.c create mode 100644 binutils-2.25/gold/testsuite/ifuncmain7.c create mode 100644 binutils-2.25/gold/testsuite/ifuncmod1.c create mode 100644 binutils-2.25/gold/testsuite/ifuncmod3.c create mode 100644 binutils-2.25/gold/testsuite/ifuncmod5.c create mode 100644 binutils-2.25/gold/testsuite/ifuncmod6.c create mode 100644 binutils-2.25/gold/testsuite/ifuncvar1.c create mode 100644 binutils-2.25/gold/testsuite/ifuncvar2.c create mode 100644 binutils-2.25/gold/testsuite/ifuncvar3.c create mode 100644 binutils-2.25/gold/testsuite/incr_comdat_test_1.cc create mode 100644 binutils-2.25/gold/testsuite/incr_comdat_test_2_v1.cc create mode 100644 binutils-2.25/gold/testsuite/incr_comdat_test_2_v2.cc create mode 100644 binutils-2.25/gold/testsuite/incr_comdat_test_2_v3.cc create mode 100755 binutils-2.25/gold/testsuite/incremental_test.sh create mode 100644 binutils-2.25/gold/testsuite/incremental_test_1.c create mode 100644 binutils-2.25/gold/testsuite/incremental_test_2.c create mode 100644 binutils-2.25/gold/testsuite/initpri1.c create mode 100644 binutils-2.25/gold/testsuite/initpri2.c create mode 100644 binutils-2.25/gold/testsuite/initpri3.c create mode 100644 binutils-2.25/gold/testsuite/justsyms.t create mode 100644 binutils-2.25/gold/testsuite/justsyms_1.cc create mode 100644 binutils-2.25/gold/testsuite/justsyms_2.cc create mode 100644 binutils-2.25/gold/testsuite/justsyms_exec.c create mode 100644 binutils-2.25/gold/testsuite/justsyms_lib.c create mode 100644 binutils-2.25/gold/testsuite/large.c create mode 100644 binutils-2.25/gold/testsuite/large_symbol_alignment.cc create mode 100644 binutils-2.25/gold/testsuite/leb128_unittest.cc create mode 100644 binutils-2.25/gold/testsuite/many_sections_test.cc create mode 100644 binutils-2.25/gold/testsuite/memory_test.s create mode 100755 binutils-2.25/gold/testsuite/memory_test.sh create mode 100644 binutils-2.25/gold/testsuite/memory_test.t create mode 100755 binutils-2.25/gold/testsuite/merge_string_literals.sh create mode 100644 binutils-2.25/gold/testsuite/merge_string_literals_1.cc create mode 100644 binutils-2.25/gold/testsuite/merge_string_literals_2.cc create mode 100644 binutils-2.25/gold/testsuite/missing_key_func.cc create mode 100755 binutils-2.25/gold/testsuite/missing_key_func.sh create mode 100644 binutils-2.25/gold/testsuite/no_version_test.c create mode 100755 binutils-2.25/gold/testsuite/no_version_test.sh create mode 100644 binutils-2.25/gold/testsuite/object_unittest.cc create mode 100644 binutils-2.25/gold/testsuite/odr_header1.h create mode 100644 binutils-2.25/gold/testsuite/odr_header2.h create mode 100644 binutils-2.25/gold/testsuite/odr_violation1.cc create mode 100644 binutils-2.25/gold/testsuite/odr_violation2.cc create mode 100644 binutils-2.25/gold/testsuite/plugin_common_test_1.c create mode 100644 binutils-2.25/gold/testsuite/plugin_common_test_2.c create mode 100644 binutils-2.25/gold/testsuite/plugin_final_layout.cc create mode 100755 binutils-2.25/gold/testsuite/plugin_final_layout.sh create mode 100644 binutils-2.25/gold/testsuite/plugin_section_order.c create mode 100644 binutils-2.25/gold/testsuite/plugin_test.c create mode 100755 binutils-2.25/gold/testsuite/plugin_test_1.sh create mode 100755 binutils-2.25/gold/testsuite/plugin_test_2.sh create mode 100755 binutils-2.25/gold/testsuite/plugin_test_3.sh create mode 100755 binutils-2.25/gold/testsuite/plugin_test_4.sh create mode 100755 binutils-2.25/gold/testsuite/plugin_test_6.sh create mode 100755 binutils-2.25/gold/testsuite/plugin_test_7.sh create mode 100644 binutils-2.25/gold/testsuite/plugin_test_7_1.c create mode 100644 binutils-2.25/gold/testsuite/plugin_test_7_2.c create mode 100755 binutils-2.25/gold/testsuite/plugin_test_tls.sh create mode 100755 binutils-2.25/gold/testsuite/pr12826.sh create mode 100644 binutils-2.25/gold/testsuite/pr12826_1.s create mode 100644 binutils-2.25/gold/testsuite/pr12826_2.s create mode 100644 binutils-2.25/gold/testsuite/pr14265.c create mode 100755 binutils-2.25/gold/testsuite/pr14265.sh create mode 100644 binutils-2.25/gold/testsuite/pr14265.t create mode 100644 binutils-2.25/gold/testsuite/protected_1.cc create mode 100644 binutils-2.25/gold/testsuite/protected_2.cc create mode 100644 binutils-2.25/gold/testsuite/protected_3.cc create mode 100644 binutils-2.25/gold/testsuite/protected_4.cc create mode 100644 binutils-2.25/gold/testsuite/protected_main_1.cc create mode 100644 binutils-2.25/gold/testsuite/protected_main_2.cc create mode 100644 binutils-2.25/gold/testsuite/protected_main_3.cc create mode 100644 binutils-2.25/gold/testsuite/relro_script_test.t create mode 100644 binutils-2.25/gold/testsuite/relro_test.cc create mode 100755 binutils-2.25/gold/testsuite/relro_test.sh create mode 100644 binutils-2.25/gold/testsuite/relro_test_main.cc create mode 100755 binutils-2.25/gold/testsuite/retain_symbols_file_test.sh create mode 100644 binutils-2.25/gold/testsuite/script_test_1.cc create mode 100644 binutils-2.25/gold/testsuite/script_test_1.t create mode 100644 binutils-2.25/gold/testsuite/script_test_10.s create mode 100755 binutils-2.25/gold/testsuite/script_test_10.sh create mode 100644 binutils-2.25/gold/testsuite/script_test_10.t create mode 100644 binutils-2.25/gold/testsuite/script_test_11.c create mode 100644 binutils-2.25/gold/testsuite/script_test_11.t create mode 100644 binutils-2.25/gold/testsuite/script_test_2.cc create mode 100644 binutils-2.25/gold/testsuite/script_test_2.t create mode 100644 binutils-2.25/gold/testsuite/script_test_2a.cc create mode 100644 binutils-2.25/gold/testsuite/script_test_2b.cc create mode 100755 binutils-2.25/gold/testsuite/script_test_3.sh create mode 100644 binutils-2.25/gold/testsuite/script_test_3.t create mode 100755 binutils-2.25/gold/testsuite/script_test_4.sh create mode 100644 binutils-2.25/gold/testsuite/script_test_4.t create mode 100644 binutils-2.25/gold/testsuite/script_test_5.cc create mode 100755 binutils-2.25/gold/testsuite/script_test_5.sh create mode 100644 binutils-2.25/gold/testsuite/script_test_5.t create mode 100755 binutils-2.25/gold/testsuite/script_test_6.sh create mode 100644 binutils-2.25/gold/testsuite/script_test_6.t create mode 100755 binutils-2.25/gold/testsuite/script_test_7.sh create mode 100644 binutils-2.25/gold/testsuite/script_test_7.t create mode 100755 binutils-2.25/gold/testsuite/script_test_8.sh create mode 100644 binutils-2.25/gold/testsuite/script_test_9.cc create mode 100755 binutils-2.25/gold/testsuite/script_test_9.sh create mode 100644 binutils-2.25/gold/testsuite/script_test_9.t create mode 100644 binutils-2.25/gold/testsuite/searched_file_test.cc create mode 100644 binutils-2.25/gold/testsuite/searched_file_test_lib.cc create mode 100644 binutils-2.25/gold/testsuite/section_sorting_name.cc create mode 100755 binutils-2.25/gold/testsuite/section_sorting_name.sh create mode 100755 binutils-2.25/gold/testsuite/split_i386.sh create mode 100644 binutils-2.25/gold/testsuite/split_i386_1.s create mode 100644 binutils-2.25/gold/testsuite/split_i386_2.s create mode 100644 binutils-2.25/gold/testsuite/split_i386_3.s create mode 100644 binutils-2.25/gold/testsuite/split_i386_4.s create mode 100644 binutils-2.25/gold/testsuite/split_i386_n.s create mode 100755 binutils-2.25/gold/testsuite/split_x86_64.sh create mode 100644 binutils-2.25/gold/testsuite/split_x86_64_1.s create mode 100644 binutils-2.25/gold/testsuite/split_x86_64_2.s create mode 100644 binutils-2.25/gold/testsuite/split_x86_64_3.s create mode 100644 binutils-2.25/gold/testsuite/split_x86_64_4.s create mode 100644 binutils-2.25/gold/testsuite/split_x86_64_n.s create mode 100644 binutils-2.25/gold/testsuite/start_lib_test_1.c create mode 100644 binutils-2.25/gold/testsuite/start_lib_test_2.c create mode 100644 binutils-2.25/gold/testsuite/start_lib_test_3.c create mode 100644 binutils-2.25/gold/testsuite/start_lib_test_main.c create mode 100755 binutils-2.25/gold/testsuite/strong_ref_weak_def.sh create mode 100644 binutils-2.25/gold/testsuite/strong_ref_weak_def_1.c create mode 100644 binutils-2.25/gold/testsuite/strong_ref_weak_def_2.c create mode 100644 binutils-2.25/gold/testsuite/test.cc create mode 100644 binutils-2.25/gold/testsuite/test.h create mode 100644 binutils-2.25/gold/testsuite/testfile.cc create mode 100644 binutils-2.25/gold/testsuite/testfile.h create mode 100644 binutils-2.25/gold/testsuite/testmain.cc create mode 100644 binutils-2.25/gold/testsuite/text_section_grouping.cc create mode 100755 binutils-2.25/gold/testsuite/text_section_grouping.sh create mode 100644 binutils-2.25/gold/testsuite/thin_archive_main.cc create mode 100644 binutils-2.25/gold/testsuite/thin_archive_test_1.cc create mode 100644 binutils-2.25/gold/testsuite/thin_archive_test_2.cc create mode 100644 binutils-2.25/gold/testsuite/thin_archive_test_3.cc create mode 100644 binutils-2.25/gold/testsuite/thin_archive_test_4.cc create mode 100644 binutils-2.25/gold/testsuite/thumb2_branch_range.t create mode 100644 binutils-2.25/gold/testsuite/thumb_bl_in_range.s create mode 100644 binutils-2.25/gold/testsuite/thumb_bl_out_of_range.s create mode 100644 binutils-2.25/gold/testsuite/thumb_bl_out_of_range_local.s create mode 100644 binutils-2.25/gold/testsuite/thumb_blx_in_range.s create mode 100644 binutils-2.25/gold/testsuite/thumb_blx_out_of_range.s create mode 100644 binutils-2.25/gold/testsuite/thumb_branch_range.t create mode 100644 binutils-2.25/gold/testsuite/tls_test.cc create mode 100644 binutils-2.25/gold/testsuite/tls_test.h create mode 100644 binutils-2.25/gold/testsuite/tls_test_c.c create mode 100644 binutils-2.25/gold/testsuite/tls_test_file2.cc create mode 100644 binutils-2.25/gold/testsuite/tls_test_main.cc create mode 100755 binutils-2.25/gold/testsuite/two_file_shared.sh create mode 100644 binutils-2.25/gold/testsuite/two_file_test.h create mode 100644 binutils-2.25/gold/testsuite/two_file_test_1.cc create mode 100644 binutils-2.25/gold/testsuite/two_file_test_1_v1.cc create mode 100644 binutils-2.25/gold/testsuite/two_file_test_1b.cc create mode 100644 binutils-2.25/gold/testsuite/two_file_test_1b_v1.cc create mode 100644 binutils-2.25/gold/testsuite/two_file_test_2.cc create mode 100644 binutils-2.25/gold/testsuite/two_file_test_2_tls.cc create mode 100644 binutils-2.25/gold/testsuite/two_file_test_2_v1.cc create mode 100644 binutils-2.25/gold/testsuite/two_file_test_main.cc create mode 100644 binutils-2.25/gold/testsuite/two_file_test_tls.cc create mode 100644 binutils-2.25/gold/testsuite/undef_symbol.cc create mode 100755 binutils-2.25/gold/testsuite/undef_symbol.sh create mode 100644 binutils-2.25/gold/testsuite/undef_symbol_main.cc create mode 100644 binutils-2.25/gold/testsuite/ver_matching_def.cc create mode 100755 binutils-2.25/gold/testsuite/ver_matching_test.sh create mode 100644 binutils-2.25/gold/testsuite/ver_test.h create mode 100644 binutils-2.25/gold/testsuite/ver_test_1.cc create mode 100755 binutils-2.25/gold/testsuite/ver_test_1.sh create mode 100644 binutils-2.25/gold/testsuite/ver_test_10.script create mode 100755 binutils-2.25/gold/testsuite/ver_test_10.sh create mode 100644 binutils-2.25/gold/testsuite/ver_test_2.cc create mode 100644 binutils-2.25/gold/testsuite/ver_test_2.script create mode 100755 binutils-2.25/gold/testsuite/ver_test_2.sh create mode 100644 binutils-2.25/gold/testsuite/ver_test_3.cc create mode 100644 binutils-2.25/gold/testsuite/ver_test_4.cc create mode 100644 binutils-2.25/gold/testsuite/ver_test_4.script create mode 100755 binutils-2.25/gold/testsuite/ver_test_4.sh create mode 100644 binutils-2.25/gold/testsuite/ver_test_5.cc create mode 100644 binutils-2.25/gold/testsuite/ver_test_5.script create mode 100755 binutils-2.25/gold/testsuite/ver_test_5.sh create mode 100644 binutils-2.25/gold/testsuite/ver_test_6.c create mode 100644 binutils-2.25/gold/testsuite/ver_test_7.cc create mode 100755 binutils-2.25/gold/testsuite/ver_test_7.sh create mode 100644 binutils-2.25/gold/testsuite/ver_test_8.script create mode 100644 binutils-2.25/gold/testsuite/ver_test_9.cc create mode 100644 binutils-2.25/gold/testsuite/ver_test_main.cc create mode 100644 binutils-2.25/gold/testsuite/ver_test_main_2.cc create mode 100644 binutils-2.25/gold/testsuite/version_script.map create mode 100644 binutils-2.25/gold/testsuite/weak_alias_test.script create mode 100644 binutils-2.25/gold/testsuite/weak_alias_test_1.cc create mode 100644 binutils-2.25/gold/testsuite/weak_alias_test_2.cc create mode 100644 binutils-2.25/gold/testsuite/weak_alias_test_3.cc create mode 100644 binutils-2.25/gold/testsuite/weak_alias_test_4.cc create mode 100644 binutils-2.25/gold/testsuite/weak_alias_test_5.cc create mode 100644 binutils-2.25/gold/testsuite/weak_alias_test_main.cc create mode 100755 binutils-2.25/gold/testsuite/weak_plt.sh create mode 100644 binutils-2.25/gold/testsuite/weak_plt_main.cc create mode 100644 binutils-2.25/gold/testsuite/weak_plt_shared.cc create mode 100644 binutils-2.25/gold/testsuite/weak_test.cc create mode 100644 binutils-2.25/gold/testsuite/weak_undef.h create mode 100644 binutils-2.25/gold/testsuite/weak_undef_file1.cc create mode 100644 binutils-2.25/gold/testsuite/weak_undef_file2.cc create mode 100644 binutils-2.25/gold/testsuite/weak_undef_test.cc create mode 100644 binutils-2.25/gold/tilegx.cc create mode 100644 binutils-2.25/gold/timer.cc create mode 100644 binutils-2.25/gold/timer.h create mode 100644 binutils-2.25/gold/tls.h create mode 100644 binutils-2.25/gold/token.h create mode 100644 binutils-2.25/gold/version.cc create mode 100644 binutils-2.25/gold/workqueue-internal.h create mode 100644 binutils-2.25/gold/workqueue-threads.cc create mode 100644 binutils-2.25/gold/workqueue.cc create mode 100644 binutils-2.25/gold/workqueue.h create mode 100644 binutils-2.25/gold/x86_64.cc create mode 100644 binutils-2.25/gold/yyscript.y (limited to 'binutils-2.25/gold') diff --git a/binutils-2.25/gold/ChangeLog b/binutils-2.25/gold/ChangeLog new file mode 100644 index 00000000..2d16bbc1 --- /dev/null +++ b/binutils-2.25/gold/ChangeLog @@ -0,0 +1,15224 @@ +2013-10-14 Alan Modra + + * output.h (Output_data_got::add_constant): Tidy. + (Output_data_got::add_constant_pair): New function. + * powerpc.cc (Output_data_got_powerpc): Override all Output_data_got + methods used so as to first call reserve_ent(). + +2013-10-11 Roland McGrath + + * powerpc.cc (Output_data_got_powerpc): Remove unused methods + add_got_entry and add_got_entry_pair. + + * configure.ac (TLS_GNU2_DIALECT): Use -Werror in test. + (HAVE_PUBNAMES): Likewise. + * configure: Regenerate. + + * testsuite/Makefile.am: Replace '-T foo' with '-Wl,-T,foo' throughout. + * testsuite/Makefile.in: Regenerate. + + * target.h (Target::adjust_elf_header, Target::do_adjust_elf_header): + Remove const from declaration. + * target.cc (Sized_target::do_adjust_elf_header): Update definition. + * sparc.cc (Target_sparc::do_adjust_elf_header): Likewise. + * output.h (Output_file_header): Remove const from member target_ + and corresponding constructor argument. + * output.cc (Output_file_header::Output_file_header): Update prototype. + (Output_file_header::do_sized_write): Use this->target_ in place + of parameters()->target(). + + * testsuite/undef_symbol.cc (Foo::get_a): New method. + + * configure.ac (MERGE_CONSTANTS_FLAG): New check. + * configure: Regenerate. + * Makefile.in: Regenerate. + * testsuite/merge_string_literals_1.c: Renamed to have .cc suffix. + * testsuite/merge_string_literals_2.c: Likewise. + * testsuite/Makefile.am + (merge_string_literals_1.o, merge_string_literals_2.o): Update deps. + (AM_CFLAGS, AM_CXXFLAGS): Use $(MERGE_CONSTANTS_FLAG) in place of + literal -fmerge-constants. + * testsuite/Makefile.in: Regenerate. + + * i386.cc (Target_i386): Remove unused member dynbss_. + * arm.cc (Target_arm): Likewise. + * powerpc.cc (Target_powerpc): Likewise. + * sparc.cc (Target_sparc): Likewise. + * tilegx.cc (Target_tilegx): Likewise. + * x86_64.cc (Target_x86_64): Likewise. + * dwarf_reader.h (Dwarf_info_reader): Remove unused members + type_signature_, type_offset_. + * plugin.h (Plugin_hook): Remove unused member layout_. + * readsyms.h (Add_symbols): Remove unused members dirpath_, dirindex_, + mapfile_. + (Read_member): Remove unused members input_objects_, symtab_, + mapfile_, layout_. + (Check_library): Remove unused member symtab_. + * archive.h (Lib_group): Remove unused member lib_. + * archive.cc (Lib_group::Lib_group): Update initializer. + * incremental.h (Incremental_binary): Remove unused member target_. + (Incremental_script_entry): Removed unused member script_. + * layout.h (Write_symbols_task): Remove unused member input_objects_. + * icf.h (Icf): Remove unused member num_tracked_relocs. + + * gold-threads.h (Once): Conditionalize member was_run_lock_ on + [ENABLE_THREADS && __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4], matching + its only use. + * gold-threads.cc (Once::Once): Likewise conditionalize initializer. + + * archive.h: Use struct rather than class for forward declaration + of Read_symbols_data. + +2013-10-07 Cary Coutant + + PR gold/16010 + * testsuite/Makefile.am (icf_test): Fix dependencies. + (icf_safe_test): Likewise. + (icf_safe_so_test): Likewise. + (large_symbol_alignment): Add empty _LDADD rule. + * testsuite/Makefile.in: Regenerate. + +2013-09-03 Pavel Chupin + + PR gold/15927 + * x86_64.cc (Target_x86_64::Scan::global): Use relative + relocation for R_X86_64_32 on x32. + +2013-08-27 Roland McGrath + + * output.cc (Output_segment::set_section_addresses): Take new + Target* argument. If target->isolate_execinstr() and the segment + is executable and starts at a target->abi_pagesize() boundary, + pad its end out to a target->abi_pagesize() boundary with code fill. + * output.h (Output_segment::set_section_addresses): Update decl. + * layout.h (Layout::check_output_data_for_reset_values): Take new + argument RELAX_OUTPUTS. + (Layout): New member relax_output_list_. + (Layout::add_relax_output): New method. + * layout.cc (Layout::Layout): Update constructor. + (Layout::reset_relax_output): New method. + (Layout::clean_up_after_relaxation): Call it. + (Layout::prepare_for_relaxation): Update caller. + (Layout::set_segment_offsets): Update callers of set_section_addresses. + Call reset_relax_output before re-processing segments for + isolate_execinstr case. + (Layout::write_data): Handle relax_output_list_. + (Layout::Relaxation_debug_check::check_output_data_for_reset_values): + Take new argument RELAX_OUTPUTS. Assert it's an empty collection. + +2013-08-23 Yuri Chornoivan + + PR binutils/15834 + * object.h: Fix typos. + +2013-08-16 Roland McGrath + + * i386.cc (Target_i386_nacl::do_code_fill): New virtual function. + * x86_64.cc (Target_x86_64_nacl::do_code_fill): New virtual function. + +2013-08-07 Cary Coutant + + Revert support for v2 DWP files: + + 2013-03-01 Cary Coutant + + Add dwp support for v2 DWARF package file format. + * dwarf_reader.cc (Dwarf_info_reader::visit_type_unit): Add + tu_length parameter. Adjust all callers. + * dwarf_reader.h (Dwarf_info_reader::visit_type_unit): Likewise. + * dwp.cc: Include dwarf.h. + (Section_bounds): New struct type. + (Unit_set): New struct type. + (Dwo_file::Dwo_file): Initialize new data member. + (Dwo_file::read_compunit_index, Dwo_file::read_typeunit_index): + Combine and rename to... + (Dwo_file::read_unit_index): ...this. + (Dwo_file::sized_read_compunit_index) + (Dwo_file::sized_read_typeunit_index): Combine and rename to... + (Dwo_file::sized_read_unit_index): ...this. + (Dwo_file::copy_section): Remove section_name, is_str_offsets + parameters; add section_id parameter. + (Dwo_file::add_cu_set, Dwo_file::add_tu_set): Combine and rename to... + (Dwo_file::add_unit_set): ...this. + (Dwo_file::shndx_map_): Remove. + (Dwo_file::sect_offsets_): New data member. + (Dwp_output_file::Dwp_output_file): Initialize new data members. + (Dwp_output_file::add_section): Rename to... + (Dwp_output_file::add_contribution): ...this. + (Dwp_output_file::add_cu_set): Combine parameters into a struct. + (Dwp_output_file::add_tu_set): Likewise. + (Dwp_output_file::Contribution): New type. + (Dwp_output_file::Section::contributions): New data member. + (Dwp_output_file::Cu_or_tu_set): Remove. + (Dwp_output_file::Section::Section): New ctor. + (Dwp_output_file::Dwp_index::Shndx_pool): Remove. + (Dwp_output_file::Dwp_index::Section_table): New type. + (Dwp_output_file::Dwp_index::Dwp_index): Initialize new data members. + (Dwp_output_file::Dwp_index::enter_set): Change type of "set" + parameter. + (Dwp_output_file::Dwp_index::shndx_pool): Remove. + (Dwp_output_file::Dwp_index::shndx_pool_end): Remove. + (Dwp_output_file::Dwp_index::section_table): New member function. + (Dwp_output_file::Dwp_index::section_table_end): New member function. + (Dwp_output_file::Dwp_index::shndx_pool_size): Remove. + (Dwp_output_file::Dwp_index::section_table_rows): New member function. + (Dwp_output_file::Dwp_index::section_table_cols): New member function. + (Dwp_output_file::Dwp_index::shndx_pool_): Remove. + (Dwp_output_file::Dwp_index::section_table_): New data member. + (Dwp_output_file::Dwp_index::section_mask_): New data member. + (Dwp_output_file::add_output_section): New member function. + (Dwp_output_file::write_new_section): New member function. + (Dwp_output_file::write_contributions): New member function. + (Dwp_output_file::section_id_map_): New data member. + (class Dwo_id_info_reader): Remove. + (class Unit_reader): New class. + (get_dwarf_section_name): New function. + (Dwo_file::read_executable): Adjust initializations of class data. + (Dwo_file::read): Add support for v2 package file format. + (Dwo_file::read_unit_index): Likewise. + (Dwo_file::sized_read_unit_index): Likewise. + (Dwo_file::copy_section): Likewise. + (Dwo_file::add_unit_set): Likewise. + (Dwp_output_file::add_output_section): Likewise. + (Dwp_output_file::add_contribution): Likewise. + (Dwp_output_file::Dwp_index::find_or_add): Use row index to check + for empty slot. + (Dwp_output_file::Dwp_index::enter_set): Add support for v2 package + file format. + (Dwp_output_file::Dwp_index::grow): Use row index to check for empty + slot. + (Dwp_output_file::initialize): Remove unused function. + (Dwp_output_file::finalize): Add support for v2 package file format. + (Dwp_output_file::write_index): Likewise. + * gdb-index.cc (Gdb_index_info_reader::visit_type_unit): Adjust + function prototype. + +2013-07-31 Cary Coutant + + * object.cc (Sized_relobj::do_output_section_address): New function. + (Sized_relobj): Instantiate explicitly. + * object.h (Object::output_section_address): New function. + (Object::do_output_section_address): New function. + (Sized_relobj::do_output_section_address): New function. + * powerpc.cc (Target_powerpc::symval_for_branch): Use it. + +2013-07-30 Cary Coutant + Sasa Stankovic + + * parameters.cc (Parameters::entry): Return target-specific entry + symbol name. + * target.h (Target::entry_symbol_name): New function. + (Target_info::entry_symbol_name): New data member. + + * arm.cc (Target_arm::arm_info): Add entry_symbol_name. + * i386.cc (Target_i386::i386_info): Likewise. + (Target_i386_nacl::i386_nacl_info): Likewise. + * sparc.cc (Target_sparc::sparc_info): Likewise. + * tilegx.cc (Target_tilegx::tilegx_info): Likewise. + * x86_64.cc: (Target_x86_64::x86_64_info) Likewise. + (Target_x86_64_nacl::x86_64_nacl_info) Likewise. + * testsuite/testfile.cc (Target_test::test_target_info): Likewise. + +2013-07-22 Sterling Augustine + + * dwarf_reader.cc (Dwarf_pubnames_table::read_section): + Convert parameter shndx to local variable. Add parameters symtab + and symtab_size. Scan over section names. Find relocation + section corresponding to current section. Create and initialize + reloc_mapper_ and reloc_type_. + (Dwarf_pubnames_table::read_header): Add assertion. Change + unit_length to off_t. Initialize member unit_length_. Fill in field + cu_offset_. + * dwarf_reader.h (Dwarf_pubnames_table::Dwarf_pubnames_table): + Initialize new fields unit_length_ and cu_offset_. + (Dwarf_pubnames_table::read_section): Update prototype. + (Dwarf_pubnames_table::cu_offset): New member function. + (Dwarf_pubnames_table::subsection_size): Likewise. + (Dwarf_pubnames_table::cu_offset_, Dwarf_pubnames_table::unit_length): + New fields. + (Dwarf_info_reader::symtab, Dwarf_info_reader::symtab_size): Make + member functions public. + * gdb_index.cc (Gdb_index_info_reader::read_pubnames_and_pubtypes): + Update comment. Rework logic. Move repeated parts to... + (Gdb_index_info_reader::read_pubtable): ...here. New function. + (Gdb_index::Gdb_index): Initialize new fields, pubnames_table_, + pubtypes_table_, and stmt_list_offset. + (Gdb_index::map_pubtable_to_dies, Gdb_index::find_pubname_offset, + Gdb_index::find_pubtype_offset, + Gdb_index::map_pubnames_and_types_to_dies): Define new functions. + (Gdb_index::pubnames_read): Update prototype and rework logic. + * gdb_index.h (Gdb_index_info_reader, Dwarf_pubnames_table): + Forward declare. + (Gdb_index::map_pubtable_to_dies, Gdb_index::find_pubname_offset, + Gdb_index::find_pubtype_offset, Gdb_index::pubnames_table) + Gdb_index::pubtypes_table, Gdb_index::map_pubnames_and_types_to_dies, + Gdb_index::map_pubtable_to_dies): + Declare functions. + (Gdb_index::pubnames_read): Update declaration. + (Gdb_index::Pubname_offset_map): New type. + (Gdb_index::cu_pubname_map_, Gdb_index::cu_pubtype_map_, + Gdb_index::pubnames_table_, Gdb_index::pubtypes_table_, + Gdb_index::stmt_list_offset): Declare. + (Gdb_index::pubnames_shndx_, Gdb_index::pubnames_offet_, + Gdb_index::pubtypes_object_, Gdb_index::pubtypes_shndx_) + Gdb_index::pubtypes_offset_): Remove. + +2013-07-19 Roland McGrath + + * options.h (General_options): Add -Trodata-segment option. + * parameters.cc (Parameters::check_rodata_segment): New function. + (Parameters::set_target_once): Call it. + * parameters.h (Parameters): Declare it (private member function). + * layout.cc (load_seg_unusable_for_headers): New function, broken + out of Layout::relaxation_loop_body. If TARGET->isolate_execinstr() + then validate rodata segment rather than text segment. + (relaxation_loop_body): Call that. + (is_text_segment): New function. Don't admit a non-executable + segment if TARGET->isolate_execinstr(). + (set_segment_offsets): Call it. Honor -Trodata-segment option. + +2013-07-15 Shawn Landden + + PR gold/15070 + * fileread.h (File_read::get_view): Clarify comment about ALIGNED. + * nacl.h (Sniff_file::View::View): Request aligned view. + +2013-07-11 Cary Coutant + + * powerpc.cc (Target_powerpc::write_branch_lookup_table): Use + correct BRLT entry size. + +2013-07-03 Alan Modra + + * powerpc.cc (Target_powerpc::Relocate::relocate): Update self-call + comment. + +2013-07-01 Cary Coutant + + * dwarf_reader.cc (Dwarf_ranges_table::read_ranges_table): Save + reloc_type_. + (Dwarf_ranges_table::read_range_list): Call lookup_reloc. + (Dwarf_ranges_table::lookup_reloc): New function. + * dwarf_reader.h (Dwarf_ranges_table::Dwarf_ranges_table): Initialize + reloc_type_. + (Dwarf_ranges_table::lookup_reloc): New function. + (Dwarf_ranges_table::reloc_type_): New data member. + +2013-06-27 Jing Yu + + PR gold/15662 + * powerpc.cc (Output_data_brlt_powerpc::reset_brlt_sizes): New + function. + (Output_data_brlt_powerpc::finalize_brlt_sizes): New function. + (Target_powerpc::do_relax): Call the above. + +2013-06-27 Cary Coutant + + * powerpc.cc (Target_powerpc::symval_for_branch): Don't assert + on garbage collected .opd section. + +2013-06-27 Alan Modra + + * powerpc.cc (Target_powerpc::do_gc_add_reference): Test dst_shndx + is non-zero. + (Target_powerpc::do_gc_mark_symbols): Likewise for sym->shndx(). + (Target_powerpc::do_function_location): Likewise for loc->shndx. + +2013-06-14 Cary Coutant + + * resolve.cc (Symbol::override_base): Don't override st_type + from plugin placeholder symbols. + (Symbol_table::resolve): Likewise. + (Symbol_table::should_override): Don't complain about TLS mismatch + if the TO symbol is a plugin placeholder. + * testsuite/Makefile.am (plugin_test_tls): New test. + * testsuite/Makefile.in: Regenerate. + * testsuite/plugin_test_tls.sh: New test script. + * testsuite/two_file_test_2_tls.cc: New test source. + * testsuite/two_file_test_tls.cc: New test source. + +2013-06-05 Alexander Ivchenko + + * layout.cc (Layout::set_segment_offsets): Taking care of the case when + the maximum segment alignment is larger than the page size. + * testsuite/Makefile.am (large_symbol_alignment): Test that Gold + correctly aligns the symbols with large alignemnt. + * testsuite/Makefile.in: Regenerate. + * testsuite/large_symbol_alignment.cc: New file. + +2013-05-30 Alexander Ivchenko + Sriraman Tallam + + * options.h (sort_section): New option. + * output.h (Input_section_sort_section_prefix_special_ordering_compare): + Rename from Input_section_sort_section_name_special_ordering_compare. + (Input_section_sort_section_name_compare): New struct. + * output.cc (Output_section::Input_section_sort_section_name_compare:: + operator()): New function. + (Output_section::sort_attached_input_sections): Use new sort function + for .text if --sort-section=name is specified. + * layout.cc (Layout::make_output_section): + Add sorting by name when --sort-section=name is specified. + * testsuite/Makefile.am (text_section_grouping): Test option + --sort-section=name. + * testsuite/Makefile.in: Regenerate. + * testsuite/section_sorting_name.cc: New file. + * testsuite/section_sorting_name.sh: New file. + +2013-05-21 Cary Coutant + + * symtab.h (Symbol::is_cxx_vtable): New function. + * target-reloc.h (relocate_section): Check for vtable symbol. + * testsuite/Makefile.am (missing_key_func.sh): New test case. + * testsuite/Makefile.in: Regenerate. + * testsuite/missing_key_func.cc: New test source. + * testsuite/missing_key_func.sh: New test script. + +2013-05-21 Cary Coutant + + * object.cc (Sized_relobj_file::get_symbol_location_info): Set + type of enclosing symbol. + (Relocate_info::location): Check symbol type when describing symbol. + * object.h (Symbol_location_info): Remove unused line_number; + add enclosing_symbol_type. + * testsuite/debug_msg.sh: Adjust expected output. + +2013-05-13 Cary Coutant + + * configure.ac: Export DEFAULT_TARGET. + * configure: Regenerate. + * Makefile.in: Regenerate. + * testsuite/Makefile.am: Add .EXPORT_ALL_VARIABLES. + * testsuite/Makefile.in: Regenerate. + * testsuite/debug_msg.sh: Delete duplicate tests. + Don't check undef_int error message match for powerpc where the + source file and line number aren't available. + +2013-05-10 Roland McGrath + + * options.h (General_options): Add --rosegment-gap option. + * options.cc (finalize): --rosegment-gap implies --rosegment. + * layout.cc (set_segment_offsets): Let user option override + target->rosegment_gap(). + +2013-05-10 Roland McGrath + + * options.h (General_options): Remove leading space from help + messages for -nostdlib and --rosegment. + +2013-05-03 Maciej W. Rozycki + + PR ld/15365 + * layout.cc (Layout::finalize): Make __ehdr_start STV_HIDDEN. + +2013-05-03 Alan Modra + + * merge.cc (Output_merge_string::do_add_input_section): Correct + scan for number of strings. Rename vars to avoid shadowing. + Include missing terminator in input_size_. + +2013-05-01 H.J. Lu + + * merge.cc (Output_merge_string::do_add_input_section): + Restore empty string handling. + +2013-05-01 Cary Coutant + + * stringpool.cc (Stringpool_template::new_key_offset): Fix + uninitialized warning. + +2013-04-29 Alexander Ivchenko + + * output.cc (Output_section::add_merge_input_section): Allow + to merge sections if the alignment is more than character size. + * merge.h (Output_merge_string::Output_merge_string): Remove + assert. + * merge.cc (Output_merge_string::do_add_input_section): Count + only not-null strings. Check the alignment of strings. + * stringpool.h + (Stringpool_template::Stringpool_template): Add + alignment as the argument. + (Stringpool_template::addralign_): New class member. + * stringpool.cc (Stringpool_template::new_key_offset): + Align non-zero length strings according to the addralign_. + (Stringpool_template::set_string_offsets): + Updating offsets according to the given alignment. + * testsuite/Makefile.am (text_section_grouping): Test if string + literals are getting merged. + * testsuite/Makefile.in: Regenerate. + * testsuite/merge_string_literals_1.c: New file. + * testsuite/merge_string_literals_2.c: Ditto. + * testsuite/merge_string_literals.sh: Ditto. + +2013-04-26 Ian Lance Taylor + + * target-reloc.h (relocate_section): If the reloc offset is out of + range, pass VIEW as NULL to relocate.relocate. + * arm.cc (Target_arm:Relocate::relocate): Check for a NULL view. + * i386.cc (Target_i386::Relocate::relocate): Likewise. + * powerpc.cc (Target_powerpc::Relocate::relocate): Likewise. + * sparc.cc (Target_sparc::Relocate::relocate): Likewise. + * tilegx.cc (Target_tilegx::Relocate::relocate): Likewise. + * x86_64.cc (Target_x86_64::Relocate::relocate): Likewise. + +2013-04-26 Geoff Pike + + * gold.cc (queue_final_tasks): invoke layout->queue_build_id_tasks(). + * layout.cc (Hash_task): New class. + (Layout::queue_build_id_tasks): New function. + (Layout::write_build_id): Handle single-thread portion of build ID + computation. (In some cases, all of it is single-threaded.) Replace + {sha1,md5}_process_bytes with {sha1,md5}_buffer to get the same + functionality in fewer lines of code. + * layout.h (Layout::queue_build_id_tasks): New function declaration. + * options.h (General_options): make "--build-id" default to tree + rather than sha1. Add two new options related to --build-id=tree: + --build-id-chunk-size-for-treehash and + --build-id-min-file-size-for-treehash. + * Makefile.am: add testing of --build-id=tree and related new options + (these tests will be invoked by "make check"). + * Makefile.in: Regenerate. + +2013-04-25 Alan Modra + + * configure.tgt: Add powerpcle and powerpc64le. + +2013-04-22 Alan Modra + + PR gold/15355 + * layout.cc (Layout::segment_precedes): Allow more than one + segment with the same type and flags. + +2013-04-15 Cary Coutant + + * layout.cc (Layout::set_relocatable_section_offsets): Don't + allocate space in file for BSS sections. + +2013-04-15 Cary Coutant + + * script-sections.cc (Orphan_output_section): Reset address + to zero after each orphaned section for relocatable links. + +2013-04-15 Cary Coutant + + * symtab.cc (Symbol_table::sized_write_globals): Subtract + section starting address for relocatable link. + * testsuite/Makefile.am (script_test_11): New test. + * testsuite/Makefile.in: Regenerate. + * testsuite/script_test_11.c: New source file. + * testsuite/script_test_11.t: New linker script. + +2013-04-13 Alan Modra + + * powerpc.cc (Stub_control::can_add_to_stub_group): Don't set + owner when sections are not adjacent and exceed group size. + (Target_powerpc::group_sections): Handle corner case. + (Target_powerpc::Branch_info::make_stub): Handle case where + stub table doesn't exist due to branches in non-exec sections. + (Target_powerpc::Relocate::relocate): Likewise. + +2013-04-11 Alan Modra + + PR gold/15354 + * powerpc.cc (Target_powerpc::make_brlt_section): Name section + .branch_lt to match bfd ld. Adjust comments throughout file. + +2013-04-04 Ian Lance Taylor + + GCC PR c++/56840 + * object.cc (do_layout_deferred_sections): Handle .eh_frame + sections before checking whether they are included in the link. + +2013-03-29 Sriraman Tallam + + * archive.cc (Archive::get_elf_object_for_member): Create the elf + object before calling the plugin claim_file handler. Pass the elf + object of the archive to the plugin. Delete the elf object if the + plugin claims the file. + +2013-03-21 Alan Modra + + * layout.cc (Layout::set_segment_offsets): Accept writable .text + segment when omagic. + +2013-03-21 Alan Modra + + * dwp.cc (Dwp_output_file::add_contribution): Avoid signed/unsigned + comparison warning. + * layout.cc (Layout::create_dynamic_symtab): Avoid "may be used + uninitialized" warning. + +2013-03-20 Alan Modra + + * symtab.h (Symbol::clear_version): New function. + * symtab.cc (Symbol_table::set_dynsym_indexes): Don't set object + is_needed by weak references. Clear version for symbols defined + in as-needed objects that are not needed. + +2013-03-15 Alan Modra + + * powerpc.cc (Target_powerpc::Scan::reloc_needs_plt_for_ifunc): Make + static and public. Add report_err param. Return false for data refs. + (Target_powerpc::rela_dyn_section): New overloaded function. + (Target_powerpc::plt_, iplt_): Elucidate. + (Output_data_plt_powerpc::entry_count): Handle current_data_size()==0. + (Output_data_plt_powerpc::do_write): Don't write .iplt. + (Output_data_plt_powerpc::plt_entry_count): Don't add .iplt entries. + (Target_powerpc::Scan::local, global): Adjust reloc_needs_plt_for_ifunc + calls. Put ifunc dynamic relocs in irela_dyn_section. Only + push_branch and make_plt_entry for ifunc syms when + reloc_needs_plt_for_ifunc. + (Target_powerpc::Relocate::relocate): Don't use plt entry value + for ifunc unless reloc_needs_plt_for_ifunc. + +2013-03-15 Alan Modra + + * gc.h (gc_process_relocs): Don't look through function descriptors. + * icf.cc (get_section_contents): Do so here instead. + +2013-03-13 Alan Modra + + * powerpc.cc (is_branch_reloc): Forward declare. + (Target_powerpc::do_can_check_for_function_pointers): New predicate. + (Target_powerpc::Scan::local_reloc_may_be_function_pointer): Return + false for 64-bit, true for 32-bit non-branch relocs. + (Target_powerpc::Scan::global_reloc_may_be_function_pointer): Likewise. + * testsuite/Makefile.am (icf_test): Use linker map file instead of + nm output. + (icf_safe_test): Generate linker map file as well as nm output. + (icf_safe_so_test): Likewise. + * testsuite/Makefile.in: Regenerate. + * testsuite/icf_test.sh: Parse linker map file to determine + section folding. + * testsuite/icf_safe_test.sh: Likewise. Expect folding for PowerPC. + * testsuite/icf_safe_so_test.sh: Likewise. + (X86_32_or_ARM_specific_safe_fold): Merge into.. + (arch_specific_safe_fold): ..this. + (X86_64_specific_safe_fold): Delete unused function. + +2013-03-12 Alan Modra + + * gc.h (gc_process_relocs): Look through function descriptors + to determine shndx, symvalue and addend used by ICF. Tidy + variable duplication. + +2013-03-11 Alan Modra + + * gold.cc (queue_middle_tasks): Move detect_odr_violations.. + * layout.cc (Layout_task_runner::run): ..to here. + * symtab.h (struct Symbol_location): Extract from.. + (class Symbol_table): ..here. + * symtab.cc (Symbol_table::linenos_from_loc): Invoke function_location. + * target.h (class Target): Add function_location and + do_function_location functions. + (class Sized_target): Add do_function_location. + * object.h (class Sized_relobj_file): Move find_shdr.. + (class Object): ..to here. + * object.cc: Likewise. Update to suit. Instantiate. + (Sized_relobj_file::find_eh_frame): Update find_shdr call. + * powerpc.cc (class Powerpc_dynobj): New. + (Target_powerpc::do_function_location): New function. + (Powerpc_relobj::do_find_special_sections): Update find_shdr call. + (Powerpc_dynobj::do_read_symbols): New function. + (Target_powerpc::do_make_elf_object): Make a Powerpc_dynobj. + +2013-03-08 Ian Lance Taylor + + * options.cc (General_options::string_to_object_format): Accept + "default". + +2013-03-08 Alan Modra + + * ehframe.h (Post_fdes) Make it a vector of Post_fde rather than + pointer to Post_fde. + (struct Post_fde): Move definition to here.. + * ehframe.cc (struct Post_fde): ..from here. + (Cie::write): Don't alloc Post_fde. + (Eh_frame::do_sized_write): Update. Don't free Post_fde. + +2013-03-07 Alan Modra + + * testsuite/discard_locals_relocatable_test.c: Add a powerpc + relocation referencing .LC0. + * testsuite/discard_locals_test.sh: Remove FIXMEs. + +2013-03-07 Alan Modra + + * testsuite/ifunc-sel.h (ifunc_sel, ifunc_one): Mark + always_inline. Add assembly for powerpc to avoid GOT. + +2013-03-07 Alan Modra + + * testsuite/script_test_10.sh: Don't test .bss section + header number. + +2013-03-06 Alan Modra + + * powerpc.cc (class Powerpc_relobj): Move some member functions. + (Target_powerpc::symval_for_branch): Add symtab param. Update + all callers. Handle folded sections. + (Target_powerpc::do_gc_add_reference): Don't cast dynamic object + to Powerpc_relobj. + (Global_symbol_visitor_opd::operator()): Likewise. + +2013-03-04 Alan Modra + + * testsuite/Makefile.am (final_layout_script.lds): Add .sbss. + * testsuite/Makefile.in: Regenerate. + +2013-03-01 Cary Coutant + + Add dwp support for v2 DWARF package file format. + * dwarf_reader.cc (Dwarf_info_reader::visit_type_unit): Add + tu_length parameter. Adjust all callers. + * dwarf_reader.h (Dwarf_info_reader::visit_type_unit): Likewise. + * dwp.cc: Include dwarf.h. + (Section_bounds): New struct type. + (Unit_set): New struct type. + (Dwo_file::Dwo_file): Initialize new data member. + (Dwo_file::read_compunit_index, Dwo_file::read_typeunit_index): + Combine and rename to... + (Dwo_file::read_unit_index): ...this. + (Dwo_file::sized_read_compunit_index) + (Dwo_file::sized_read_typeunit_index): Combine and rename to... + (Dwo_file::sized_read_unit_index): ...this. + (Dwo_file::copy_section): Remove section_name, is_str_offsets + parameters; add section_id parameter. + (Dwo_file::add_cu_set, Dwo_file::add_tu_set): Combine and rename to... + (Dwo_file::add_unit_set): ...this. + (Dwo_file::shndx_map_): Remove. + (Dwo_file::sect_offsets_): New data member. + (Dwp_output_file::Dwp_output_file): Initialize new data members. + (Dwp_output_file::add_section): Rename to... + (Dwp_output_file::add_contribution): ...this. + (Dwp_output_file::add_cu_set): Combine parameters into a struct. + (Dwp_output_file::add_tu_set): Likewise. + (Dwp_output_file::Contribution): New type. + (Dwp_output_file::Section::contributions): New data member. + (Dwp_output_file::Cu_or_tu_set): Remove. + (Dwp_output_file::Section::Section): New ctor. + (Dwp_output_file::Dwp_index::Shndx_pool): Remove. + (Dwp_output_file::Dwp_index::Section_table): New type. + (Dwp_output_file::Dwp_index::Dwp_index): Initialize new data members. + (Dwp_output_file::Dwp_index::enter_set): Change type of "set" + parameter. + (Dwp_output_file::Dwp_index::shndx_pool): Remove. + (Dwp_output_file::Dwp_index::shndx_pool_end): Remove. + (Dwp_output_file::Dwp_index::section_table): New member function. + (Dwp_output_file::Dwp_index::section_table_end): New member function. + (Dwp_output_file::Dwp_index::shndx_pool_size): Remove. + (Dwp_output_file::Dwp_index::section_table_rows): New member function. + (Dwp_output_file::Dwp_index::section_table_cols): New member function. + (Dwp_output_file::Dwp_index::shndx_pool_): Remove. + (Dwp_output_file::Dwp_index::section_table_): New data member. + (Dwp_output_file::Dwp_index::section_mask_): New data member. + (Dwp_output_file::add_output_section): New member function. + (Dwp_output_file::write_new_section): New member function. + (Dwp_output_file::write_contributions): New member function. + (Dwp_output_file::section_id_map_): New data member. + (class Dwo_id_info_reader): Remove. + (class Unit_reader): New class. + (get_dwarf_section_name): New function. + (Dwo_file::read_executable): Adjust initializations of class data. + (Dwo_file::read): Add support for v2 package file format. + (Dwo_file::read_unit_index): Likewise. + (Dwo_file::sized_read_unit_index): Likewise. + (Dwo_file::copy_section): Likewise. + (Dwo_file::add_unit_set): Likewise. + (Dwp_output_file::add_output_section): Likewise. + (Dwp_output_file::add_contribution): Likewise. + (Dwp_output_file::Dwp_index::find_or_add): Use row index to check + for empty slot. + (Dwp_output_file::Dwp_index::enter_set): Add support for v2 package + file format. + (Dwp_output_file::Dwp_index::grow): Use row index to check for empty + slot. + (Dwp_output_file::initialize): Remove unused function. + (Dwp_output_file::finalize): Add support for v2 package file format. + (Dwp_output_file::write_index): Likewise. + * gdb-index.cc (Gdb_index_info_reader::visit_type_unit): Adjust + function prototype. + +2013-03-01 Cary Coutant + + * dwarf_reader.cc (Dwarf_info_reader::check_buffer): Move + function into class definition in header file. + (Dwarf_info_reader::warn_corrupt_debug_section): New function. + * dwarf_reader.h (Dwarf_info_reader::warn_corrupt_debug_section): + New function. + (Dwarf_info_reader::check_buffer): Move here from .cc file. + +2013-02-28 Alan Modra + + * target.h (Target::plt_fde_location, do_plt_fde_location): Declare. + * target.cc (Target::do_plt_fde_location): New function. + * ehframe.h (class FDE): Add post_map field to u_.from_linker, + accessor function, and constructor param. + (struct Post_fde, Post_fdes): Declare. + (Cie::write): Add post_fdes param. + * ehframe.cc (Fde::write): Use plt_fde_location. + (struct Post_fde): Define. + (Cie::write): Stash FDEs added post merge mapping. + (Eh_frame::add_ehframe_for_plt): Assert no new CIEs after mapping. + Adjust Fde constructor call. Bump final_data_size_ for post map FDEs. + (Eh_frame::do_sized_write): Arrange to write post map FDES after + other FDEs. + * powerpc.cc (Target_powerpc::do_plt_fde_location): New function. + (Target_powerpc::has_glink): New function. + (Target_powerpc::do_relax): Add eh_frame info for stubs. + (struct Eh_cie, eh_frame_cie, glink_eh_frame_fde_64, + glink_eh_frame_fde_32, default_fde): New data. + (Stub_table::eh_frame_added_): New var. + (Stub_table::find_long_branch_entry, stub_address, stub_offset): + Make const. + (Stub_table::add_eh_frame): New function. + (Output_data_glink::add_eh_frame): New function. + (Target_powerpc::make_glink_section): Call add_eh_frame. + +2013-02-15 Ian Lance Taylor + + * options.h (DEFINE_uint64_alias): Define. + (class General_options): Add -Ttext-segment as an alias for + -Ttext. + +2013-02-15 Alan Modra + + * powerpc.cc (Stub_table::plt_off): New function, extracted from.. + (Stub_table::do_write): ..here, two places. + (Stub_table::plt_call_size): Use it here too. + +2013-02-11 Ian Lance Taylor + + * descriptors.cc (Descriptors::close_all): New function. + * descriptors.h (class Descriptors): Declare close_all. + (close_all_descriptors): New inline function. + * plugin.cc: Include "descriptors.h". + (Plugin_manager::cleanup): Call close_all_descriptors. + +2013-02-06 Alan Modra + + * README: Update coding style link. + +2013-01-28 Cary Coutant + + * dwp.cc (File_list): New typedef. + (Dwo_name_info_reader): New class. + (Dwo_id_info_reader::Dwo_id_info_reader): Remove unused parameters. + (Dwo_id_info_reader::visit_top_die): Remove unused member function. + (Dwo_file::~Dwo_file): Delete input_file_ after obj_. + (Dwo_file::read_executable): New function. + (Dwo_file::read): Move common setup code to ... + (Dwo_file::make_object): ... here. + (dwp_options): Add --exec/-e. + (usage): Likewise. + (main): Likewise. + +2013-01-24 Sriraman Tallam + + * layout.cc (Layout::layout): Check for option text_reorder. + (Layout::make_output_section): Ditto. + * options.h (text_reorder): New option. + * output.cc (Input_section_sort_compare): Remove special ordering + of section names. + (Output_section:: + Input_section_sort_section_name_special_ordering_compare:: + operator()): New function. + (Output_section::sort_attached_input_sections): Use new sort function + for .text. + * output.h (Input_section_sort_section_name_special_ordering_compare): + New struct. + * testsuite/Makefile.am (text_section_grouping): Test option + --no-text-reorder + * testsuite/Makefile.in: Regenerate. + * testsuite/text_section_grouping.sh: Check order of functions without + default text reordering. + +2013-01-18 Mike Frysinger + + * options.h (General_options): Change default to true for new_dtags. + +2013-01-18 Mike Frysinger + + * layout.cc (Layout::finish_dynamic_section): Only add DT_RPATH + when enable_new_dtags is false. Only add DT_RUNPATH when + enable_new_dtags is true. + +2013-01-17 Serge Pavlov + + * powerpc.cc (Stub_table::find_plt_call_entry): Make types + used in declaration and definition consistent. + (Target_powerpc::symval_for_branch): Ditto. + +2013-01-16 Sriraman Tallam + + * testsuite/plugin_final_layout.cc: Fix comment. + +2013-01-16 Sriraman Tallam + + * layout.cc (Layout::layout): Do not do default sorting for + text sections when section ordering is specified. + (make_output_section): Ditto. + * testsuite/plugin_final_layout.cc: Name the function sections + to catch reordering issues. + +2013-01-15 Alan Modra + + * powerpc.cc (Target_powerpc::do_relax): Default shared libs to + plt-thread-safe. + +2013-01-15 Alan Modra + + * testsuite/Makefile.am (final_layout_script.lds): Handle .got section. + * testsuite/Makefile.in: Regenerate. + +2013-01-14 Alan Modra + + * testsuite/Makefile.am (MOSTLYCLEANFILES): Add various output files. + * testsuite/Makefile.in: Regenerate. + +2013-01-11 Pavel Chupin + + PR bfd/14430 + Fix mingw gold build with plugins enabled + * Makefile.am: Replace -ldl with @DLOPEN_LIBS@. + * configure.ac: Export DLOPEN_LIBS and add headers check. + * plugin.cc: Handle non-dlfcn case. + * Makefile.in: Regenerate. + * config.in: Regenerate. + * configure: Regenerate. + * testsuite/Makefile.in: Regenerate. + +2013-01-09 Sriraman Tallam + + * output.h (sort_attached_input_sections): Change to be public. + * script-sections.cc + (Output_section_definition::set_section_addresses): Sort + attached input sections according to section order before linker + script assigns section addresses. + (Orphan_output_section::set_section_addresses): Sort + attached input sections according to section order before linker + script assigns section addresses. + * Makefile.am (final_layout.sh): Use a simple linker script to + check if section ordering still works. + * Makefile.in: Regenerate. + +2013-01-09 Ben Cheng + + * arm.cc (Target_arm::attributes_accept_div): New function. + (Target_arm::attributes_forbid_div): New function. + (Target_arm::merge_object_attributes): Merge the Tag_DIV_use + attribute using the same new functions as what bfd/elf32_arm.c + does. + +2013-01-07 Cary Coutant + + PR gold/14993 + * output.cc (Output_section::add_input_section): For incremental + updates, don't track input sections that are allocated from patch + space. + +2013-01-07 H.J. Lu + Ian Lance Taylor + + PR gold/14897 + * configure.ac (--enable-ld): Removed. + (install_as_default): Set to yes only for --enable-gold=default + or --disable-ld. + * configure: Regenerated. + +2013-01-07 H.J. Lu + + * options.h (General_options): Add -fuse-ld= for GCC linker + option compatibility. + +2013-01-04 Cary Coutant + + * configure.ac: Fix typo restoring CXXFLAGS. + * configure: Regenerate. + +2013-01-04 Cary Coutant + + * testsuite/Makefile.am (CXXLINK_S): New macro. + (debug_msg_so.err, debug_msg_ndebug.err): Use CXXLINK_S. + * testsuite/Makefile.in: Regenerate. + +2013-01-02 H.J. Lu + + * version.cc (print_version): Update copyright year to 2013. + +2012-12-20 Ian Lance Taylor + + * layout.cc (Layout::special_ordering_of_input_section): New + function. + (Layout::layout): If input section requires special ordering, must + sort input sections. + (Layout::make_output_section): May sort .text input sections. + (Layout::is_section_name_prefix_grouped): Remove. + * layout.h (class Layout): Declare + special_ordering_of_input_section. Don't declare + is_section_name_prefix_grouped. + * output.cc (Output_section::add_input_section): Revert last + change. + (Output_section::Input_section_sort::match_file_name): Don't crash + if called on output section data. + (Output_section::Input_section_sort_compare): Sort based on + special ordering. + (Output_section::Input_section_sort_section_order_index_compare): + Revert last patch. + (Output_section::sort_attached_input_sections): Likewise. + +2012-12-18 Sriraman Tallam + + * layout.cc (Layout::is_section_name_prefix_grouped): New function. + * layout.h (Layout::is_section_name_prefix_grouped): New function. + * output.cc (Output_section::add_input_section): Check if section + name contains special prefix. Keep input sections to sort such + sections. + (Output_section::Input_section_sort_section_order_index_compare + ::operator()): Group sections according to prefixes. + (Output_section::sort_attached_input_sections): Add condition to + Input_section_entry constructor call. + * testsuite/Makefile.am (text_section_grouping): New test. + * testsuite/Makefile.in: Regenerate. + * testsuite/text_section_grouping.cc: New file. + * testsuite/text_section_grouping.sh: New file. + +2012-12-17 Nick Clifton + + * Makefile.am: Add copyright notice. + * NEWS: Likewise. + * README: Likewise. + * configure.ac: Likewise. + * ftruncate.c: Likewise. + * Makefile.in: Regenerate. + +2012-12-14 Cary Coutant + + * testsuite/Makefile.am (exception_separate_shared_12_test): Add + --no-as-needed flag. + (exception_separate_shared_12_test): Likewise. + (incremental_copy_test): Likewise. + * testsuite/Makefile.in: Regenerate. + +2012-12-14 Cary Coutant + + * dwp.cc (Dwp_output_file::add_cu_set): Check for duplicate CUs. + (Dwp_output_file::Dwp_index::enter_set): Add assert. + +2012-12-12 Alan Modra + + * powerpc.cc (class Track_tls): New. + (class Relocate, class Scan): Inherit Track_tls. + (Target_powerpc::Scan::local, global): Track tls optimization + and avoid creating plt entry for __tls_get_addr if all uses + are optimized away. + (Target_powerpc::Relocate::relocate): Update to use Track_tls. + +2012-12-12 Alan Modra + + * options.h (General_options): Add --toc-sort/--no-toc-sort. + Replace no_toc_optimize with toc_optimize. + * output.h (Output_section::input_sections): Provide non-const variant. + * powerpc.cc (Powerpc_relobj::has_small_toc_reloc_, + set_has_small_toc_reloc, has_small_toc_reloc): New variable and + accessors. + (Target_powerpc::Scan::local, global): Call set_has_small_toc_reloc. + (class Sort_toc_sections): New. + (Target_powerpc::do_finalize_sections): Sort toc sections. + (Target_powerpc::Relocate::relocate): Update toc_optimize test. + +2012-12-10 Roland McGrath + + * testsuite/binary_unittest.cc (read_all): New function. + (Sized_binary_test): Use it instead of ::read. + * fileread.cc (do_read): Don't assume pread always reads the whole + amount in a single call. + +2012-12-10 Alan Modra + + * powerpc.cc (Target_selector_powerpc::Target_selector_powerpc): + Set EM_PPC64 or EM_PPC here. + (Target_selector_powerpc::do_recognize): Delete. + +2012-12-10 Alan Modra + + * powerpc.cc (Powerpc_relobj::Powerpc_relobj): Init has14_ and + stub_table_. + (Target_powerpc::Branch_info::make_stub): Don't omit addend. + +2012-12-07 Roland McGrath + + * testsuite/binary_unittest.cc (Sized_binary_test): + Use open_descriptor rather than ::open. + +2012-12-07 Alan Modra + + * powerpc.cc (Stub_table::do_write): Delete redundant Address + typedef and invalid_address constant. + (Output_data_glink, Stub_table, Target_powerpc): Explicitly + instantiate constants. + +2012-12-06 Roland McGrath + + * configure.ac (HAVE_ZLIB): Use AM_ZLIB instead of AC_SEARCH_LIBS. + Use $ac_cv_header_zlib_h = yes as the condition in AM_CONDITIONAL. + * aclocal.m4: Regenerate. + * configure: Regenerate. + * Makefile.in: Regenerate. + * testsuite/Makefile.in: Regenerate. + +2012-12-07 Alan Modra + + * options.h (General_options): Add no_toc_optimize. + * powerpc.cc (ok_lo_toc_insn): New function. + (Target_powerpc::Relocate::relocate): Optimize toc access sequences. + +2012-12-06 Alan Modra + + * options.h (General_options): Add plt_align, plt_static_chain, + plt_thread_safe. Update stub_group_size help text. + * powerpc.cc (Target_powerpc::plt_thread_safe): New access function + for new plt_thread_safe_ var. + (use_plt_offset): Correct comments. + (Target_powerpc::do_relax): Look for thread creation symbols to + determine default plt_thread_safe value. Clear plt call stubs + as well as branch stubs each iteration. + (add_2_2_11, add_12_12_11, bnectr_p4, cmpldi_2_0, xor_11_11_11): New + insn constants. + (l, hi, ha, write_insn): Move earlier. + (Stub_table): Delete prev_size, add last_plt_size and last_branch_size. + (Stub_table::clear_stubs): Rename from clear_long_branch_stubs, clear + plt stubs too. + (Stub_table::update_size): Adjust. + (Stub_table::prev_size, set_prev_size): Delete. + (Stub_table::stub_align): Let --plt-align affect result. + (Stub_table::plt_call_size): Calculate sizes for various stubs. + (Stub_table::branch_stub_size): Use last_plt_size in address calc. + (Stub_table::add_plt_call_stub): Pass iterator to plt_call_size. + (Stub_table::do_write): Support more stub variants. + +2012-12-04 Alan Modra + + * powerpc.cc (Powerpc_relobj::do_scan_relocs): Delete. + (Target_powerpc::do_define_standard_symbols): New function. + +2012-12-03 Alan Modra + + * output.h: Formatting, whitespace. + +2012-12-03 Alan Modra + + * layout.h (Layout::get_executable_sections): Declare. + * layout.cc (Layout::get_executable_sections): New function. + * arm.cc (Target_arm::group_sections): Use it. + (Arm_output_section::group_sections): Delete now redundant test. + * output.cc (Output_reloc::Output_reloc): Add is_relative. + param to handle relative relocs. + * output.h (Output_reloc::Output_reloc ): Likewise. + (Output_data_reloc::add_absolute): Adjust. + (Output_data_reloc::add_relative): New function. + (Output_data::reset_data_size): New function. + (Output_relaxed_input_section::set_relobj, set_shndx): New functions. + (Output_section::set_addralign): New function. + (Output_section::checkpoint_set_addralign): New function. + (Output_section::clear_section_offsets_need_adjustment): New function. + (Output_section::input_sections): Make public. + * powerpc.cc (class Output_data_brlt_powerpc): New. + (class Stub_table, class Stub_control): New. + (Powerpc_relobj::has14_, set_has_14bit_branch, has_14bit_branch, + stub_table_, set_stub_table, stub_table): New vectors and accessor + functions. + (Target_powerpc::do_may_relax, do_relax, push_branch, + new_stub_table, stub_tables, brlt_section, group_sections, + add_branch_lookup_table, find_branch_lookup_table, + write_branch_lookup_table, make_brlt_section): New functions. + (Target_powerpc::struct Sort_sections, class Branch_info): New. + (Target_powerpc::brlt_section_, stub_tables_, branch_lookup_table_, + branch_info_): New vars. + (Target_powerpc::make_plt_entry, make_local_ifunc_plt_entry): Don't + make call stubs here. + (Output_data_glink): Remove all call stub handling from this class. + (Target_powerpc::Scan::local, global): Save interesting branch + relocs and relocs for ifunc. Adjust calls to plt entry functions. + (Target_powerpc::do_finalize_sections): Only make reg save/restore + functions on final link. + (Target_powerpc::Relocate::relocate): Adjust lookup of call stubs. + Handle long branch destinations too. + (Target_powerpc::do_dynsym_value, do_plt_address_for_global, + do_plt_address_for_local): Adjust lookup of plt call stubs. + +2012-11-30 Alan Modra + + * powerpc.c (Target_powerpc::Scan::global): Don't emit relative + relocs against protected symbols when building 32-bit shared libs. + +2012-11-30 Alan Modra + + * powerpc.cc (Target_powerpc::make_plt_section): Add symtab + param. Call got_section() to make .got. Update all callers + and their callers and so on. + +2012-11-30 Alan Modra + + * powerpc.cc (Powerpc_relobj::do_scan_relocs): Make STB_LOCAL + _GLOBAL_OFFSET_TABLE_ rather than STB_WEAK. + (Output_data_got_powerpc::make_header): Update _GLOBAL_OFFSET_TABLE_ + value if it already exists. + +2012-11-19 H.J. Lu + + PR gold/14858 + * x86_64.cc (Relocate::tls_ld_to_le): Support x32. + +2012-11-14 Roland McGrath + + * arm.cc (Output_data_plt_arm_nacl::first_plt_entry): Use bic rather + than bfc instruction for data sandboxing. + +2012-11-08 Alan Modra + + * po/POTFILES.in: Regenerate. + +2012-11-05 Alan Modra + + * configure.ac: Apply 2012-09-10 change to config.in here. + * configure: Regenerate. + +2012-11-05 Alan Modra + + * powerpc.cc (Powerpc_relobj): Delete "Offset" typedef. + (struct Opd_ent): Use "Address" rather than "Offset". + (Output_data_got_powerpc::got_base_offset): Return Valtype. + (Target_powerpc::got_section): Make public. + (Target_powerpc::scan_relocs): Move code setting symbols.. + (Powerpc_relobj::do_scan_relocs): ..to here, new function. + Create _SDA_BASE_ only when referenced. + +2012-11-02 Roland McGrath + + * i386.cc (Target_i386::relocate_relocs): Remove extraneous typename + from last change. + +2012-11-01 Roland McGrath + + * target.h (Sized_target::relocate_relocs): Use Elf_Off + for offset_in_output_section parameter. + (Sized_target::relocate_special_relocatable): Likewise. + * arm.cc (Target_arm::relocate_relocs): Likewise. + (Target_arm::relocate_special_relocatable): Likewise. + * i386.cc (Target_i386::relocate_relocs): Likewise. + * powerpc.cc (Target_powerpc::relocate_relocs): Likewise. + * sparc.cc (Target_sparc::relocate_relocs): Likewise. + * target-reloc.h (relocate_relocs): Likewise. + * testsuite/testfile.cc (Target_test): Likewise. + * tilegx.cc (Target_tilegx::relocate_relocs): Likewise. + * x86_64.cc (Target_x86_64::relocate_relocs): Likewise. + + * system.h: Move inclusion of to after in + [ENABLE_NLS] section, and separately at top of [!ENABLE_NLS] section. + + * descriptors.cc (set_close_on_exec): Add ATTRIBUTE_UNUSED to the + parameter, which is unused in the [!F_SETFD] case. + + * dwarf_reader.cc (Sized_elf_reloc_mapper::symbol_section): Cast + SYMNDX to off_t before comparing it to this->data_size(). + * output.cc (Output_symtab_xindex::endian_do_write): Likewise. + * incremental.cc (Output_section_incremental_inputs::do_write): + Cast GLOBAL_SYM_COUNT to off_t before comparing it to SYMTAB_SIZE. + + * nacl.cc: Include "libiberty.h" for vasprintf declaration. + +2012-10-30 Steve McIntyre + + * gold.cc (Target_arm::do_adjust_elf_header): Add the + hard-float/soft-float ABI flag as appropriate for ET_DYN/ET_EXEC + in EABI_VER5. + +2012-10-29 Cary Coutant + + * dwp.cc (usage): Add file and exit status parameters; + add --help and --version options. + (print_version): New function. + (main): Add --help and --version options. + +2012-10-25 H.J. Lu + + * testsuite/Makefile.am (MOSTLYCLEANFILES): Add + final_layout_sequence.txt. + * testsuite/Makefile.in: Regenerated. + +2012-10-25 H.J. Lu + + * testsuite/Makefile.am (COMPILE1): New variable. Renamed from + COMPILE generated by automake. + (LINK1): Likewise. + (CXXCOMPILE1): Likewise. + (CXXLINK1): Likewise. + (COMPILE): Strip out -Wp,-D_FORTIFY_SOURCE= from COMPILE1. + (LINK): Likewise. + (CXXCOMPILE): Likewise. + (CXXLINK): Likewise. + * testsuite/Makefile.in: Regenerated. + +2012-10-25 H.J. Lu + + * dwp.cc (Dwo_file::record_target_info): Issue a fatal error + on bad fwrite return. + +2012-10-25 H.J. Lu + + * dwp.cc (Dwo_file::remap_str_offset): Use section_offset_type + on val. + +2012-10-23 Cary Coutant + + * testsuite/Makefile.am (TEST_OBJCOPY): New macro. + * testsuite/Makefile.in: Regenerate. + * testsuite/dwp_test.h: New source file. + * testsuite/dwp_test_1.cc: New source file. + * testsuite/dwp_test_1.s: New source file. + * testsuite/dwp_test_1.sh: New source file. + * testsuite/dwp_test_1b.cc: New source file. + * testsuite/dwp_test_1b.s: New source file. + * testsuite/dwp_test_2.cc: New source file. + * testsuite/dwp_test_2.s: New source file. + * testsuite/dwp_test_2.sh: New source file. + * testsuite/dwp_test_main.cc: New source file. + * testsuite/dwp_test_main.s: New source file. + +2012-10-23 Cary Coutant + + * dwp.h: New header file. + * dwp.cc: New source file. + * gold.h: Move shared declarations to system.h. + * system.h: New header file. + * Makefile.am: Add dwp. + * Makefile.in: Regenerate. + +2012-10-23 Cary Coutant + + * dwarf_reader.cc (Dwarf_ranges_table::read_range_list): Call + Dwarf_info_reader::read_from_pointer. + (Dwarf_pubnames_table::read_header): Likewise. + (Dwarf_pubnames_table::next_name): Likewise. + (Dwarf_die::read_attributes): Likewise. + (Dwarf_die::skip_attributes): Likewise. + (Dwarf_info_reader::read_from_pointer): New function template. + * dwarf_reader.h (Dwarf_ranges_table): Add dwinfo_. + (Dwarf_pubnames_table): Likewise. + (Dwarf_info_reader::read_from_pointer): New function template. + * gdb-index.cc (Gdb_index_info_reader): Adjust call to + Dwarf_pubnames_table ctor. + +2012-10-23 Cary Coutant + + * dwarf_reader.cc (Dwarf_info_reader::do_parse): Use stored + abbrev_shndx. + * dwarf_reader.h (Dwarf_info_reader::Dwarf_info_reader): Initialize + abbrev_shndx_. + (Dwarf_info_reader::set_abbrev_shndx): New method. + (Dwarf_info_reader::abbrev_shndx_): New data member. + +2012-10-23 Cary Coutant + + * dwarf_reader.cc (make_elf_reloc_mapper): Check size and endianness + from object, not parameters. + (Dwarf_info_reader::parse): Likewise. + * object.h (Relobj::elfsize, Relobj::is_big_endian): New methods. + (Relobj::do_elfsize, Relobj::do_is_big_endian): New methods. + (Sized_relobj::do_elfsize, Sized_relobj::do_is_big_endian): New + methods. + +2012-10-23 Cary Coutant + + * fileread.cc (Input_file::Input_file): New constructor. + * fileread.h (class Input_file): Add new constructor. + +2012-10-18 Alan Modra + + PR gold/14727 + * object.cc (Relobj::is_section_name_included): Also match + .sdata personality section. + +2012-10-18 Alan Modra + + * target-reloc.h (class Default_comdat_behavior): New, package up.. + (get_comdat_behaviour): ..this. + (relocate_section): Add Relocate_comdat_behavior template arg, + adjust code to suit. + * arm.cc (Target_arm::relocate_section): Adjust to suit. + (Target_arm::scan_reloc_section): Likewise. + * i386.cc (Target_i386::relocate_section): Likewise. + * sparc.cc (Target_sparc::relocate_section): Likewise. + * tilegx.cc (Target_tilegx::relocate_section): Likewise. + * x86_64.cc (Target_x86_64::relocate_section): Likewise. + * powerpc.cc (class Relocate_comdat_behavior): New. + (Target_powerpc::relocate_section): Don't zap opd relocs. Supply + gold::relocate_section with new template arg. + +2012-10-18 Alan Modra + + * powerpc.cc (Target_powerpc::Scan::local, global): Always emit + dynamic relocs for GOT_TPREL got entries, without symbol if + resolving locally. + (Target_powerpc::do_gc_add_reference): Don't add for dynamic objects. + (Target_powerpc::scan_relocs): Define _GLOBAL_OFFSET_TABLE_ early. + (Target_powerpc::Relocate:relocate): REL32 reloc may be unaligned. + +2012-10-17 Alan Modra + + PR gold/14726 + * gold.cc (queue_middle_tasks): Call gc_mark_symbol on _init and _fini. + +2012-10-16 Sriraman Tallam + + * layout.cc (Layout::include_section): Keep sections marked + SHF_EXCLUDE when doing relocatable links. + +2012-10-16 Alan Modra + + * powerpc.cc (Target_powerpc::define_save_restore_funcs): New func. + (Target_powerpc::do_finalize_sections): Call it. + (Output_data_save_res): New class and supporting functions. + (Target_powerpc::symval_for_branch): Only look up .opd entry for + normal symbols defined in object files. + +2012-10-12 Alan Modra + + * powerpc.cc (Powerpc_relobj::add_gc_mark, process_gc_mark): New. + (struct Opd_ent): Make "discard" a bit field. Add "gc_mark". + (Target_powerpc::do_gc_mark_symbol): Delay marking function code + section if scan_opd_relocs not yet called. + (Target_powerpc::gc_process_relocs): Call process_gc_mark. + +2012-10-12 Alan Modra + + * powerpc.cc (Output_data_plt_powerpc::add_entry, add_ifunc_entry, + add_local_ifunc_entry): Revert last change. + (Target_powerpc::make_plt_entry, make_local_ifunc_plt_entry): Likewise. + +2012-10-05 Alan Modra + + * powerpc.cc (Target_powerpc::do_plt_address_for_local, + do_plt_address_for_global): New functions. + (Output_data_got_powerpc::do_write): Don't segfault when linking + statically. + (Output_data_plt_powerpc::add_entry, add_ifunc_entry, + add_local_ifunc_entry): Return true on adding entry.. + (Target_powerpc::make_plt_entry): ..use to avoid unnecessary + glink->add_entry call. Remove unused symtab param. Adjust calls. + (Target_powerpc::make_local_ifunc_plt_entry): Likewise. + (Target_powerpc::make_iplt_section): Remove symtab param. Don't + set up symbols here. + (Target_powerpc::do_finalize_sections): Instead set up __rela_iplt + syms here. Do so even when no .iplt. Don't segfault when linking + statically. + (Output_data_glink::add_entry, find_entry): Rearrange params. Add + new variants without reloc param. + (Glink_sym_ent::Glink_sym_ent): Likewise. + (Target_powerpc::Scan::reloc_needs_plt_for_ifunc): Accept any + reloc when refs will resolve to plt call stub. + (Target_powerpc::Scan::local): Correct ifunc handling. Allow + R_PPC_PLTREL24 to resolve locally. + (Target_powerpc::Scan::global): Correct ifunc handling. + (Target_powerpc::Relocate::relocate): Correct local sym glink + lookup. Don't destroy "value" when we have a plt call stub, + and when checking plt call validity. + (Target_powerpc::do_dynsym_value): Simplify. + +2012-10-05 Alan Modra + + * i386.cc (Output_data_plt_i386::address_for_global, + address_for_local): Add plt offset to returned value. Adjust uses. + * sparc.cc (Output_data_plt_sparc::address_for_global, + address_for_local): Likewise. + * tilegx.cc (Output_data_plt_tilegx::address_for_global, + address_for_local): Likewise. + * x86_64.cc (Output_data_plt_x86_64::address_for_global, + address_for_local): Likewise. + * target.h (Target::plt_address_for_global, plt_address_for_local): + Update comment. + * output.cc (Output_reloc::symbol_value): Don't add plt offset here. + (Output_data_got::Got_entry::write): Nor here. + * output.h: Comment fix. + +2012-10-02 Jiong Wang + + * tilegx.cc (Target_tilegx::do_finalize_sections): Adjust + global_offset_table_ value for larget got. + (Target_tilegx::Relocate::relocate): Handle adjusted got value. + +2012-09-29 Alan Modra + + * powerpc.cc (Target_powerpc::iplt_): New output section. + (Target_powerpc::iplt_section, make_iplt_section, + reloc_needs_plt_for_ifunc, make_local_ifunc_plt_entry): New functions. + (Target_powerpc::make_plt_entry): Handle ifunc syms. + Target_powerpc::plt_entry_count): Count iplt entries too. + (Output_data_plt_powerpc::Output_data_plt_powerpc): Don't create + reloc section in constructor. New params. + (Target_powerpc::make_plt_section): Create reloc section here instead. + (Output_data_plt_powerpc::add_ifunc_entry, add_local_ifunc_entry): New + functions. + (Output_data_plt_powerpc::initial_plt_entry_size_, name_): New vars. + (Output_data_glink::add_entry, find_entry): New functions to + deal with local syms. + (Glink_sym_ent): Add support for local syms. + (Output_data_glink::do_write): Handle ifunc plt entries. + (Target_powerpc::Scan::get_reference_flags): Handle more relocs. + (Target_powerpc::Scan::local, global): Handle ifunc syms. + (Target_powerpc::Relocate::relocate): Likewise. + (Target_powerpc::do_dynsym_value): Use glink stub, not plt entry. + +2012-09-25 Alan Modra + + * object.h (Sized_relobj_file::adjust_local_symbol, + do_adjust_local_symbol): New functions. + * object.cc (Sized_relobj_file::do_count_local_symbols): Use the above. + * powerpc.cc (Powerpc_relobj::do_adjust_local_symbol): New function. + (Powerpc_relobj::scan_opd_relocs): Warn on unexpected opd relocs + and irregular opd entry spacing. + (Powerpc_relobj::do_read_relocs): Add opd size checks. + (Global_symbol_visitor_opd): New functor. + (Target_powerpc::do_finalize_sections): Omit global symbols defined + on deleted opd entries. + +2012-09-15 Jiong Wang + + * tilegx.cc: New file. + * Makefile.am (TARGETSOURCES): Add tilegx.cc + (ALL_TARGETOBJS): Add tilegx.$(OBJEXT) + * configure.tgt: Add entries for tilegx*. + * configure.ac: Likewise. + * Makefile.in: Rebuild. + * configure: Likewise. + * testsuite/icf_safe_test.sh (arch_specific_safe_fold): Handle + tilegx. + +2012-09-13 Alan Modra + + * target-reloc.h (scan_relocs): Call scan.local for relocs + against symbols in discarded sections. Pass is_discarded + param. + * arm.cc, * i386.cc, * sparc.cc, * x86_64.cc (Target_*::Scan::local): + Add is_discarded param. + * powerpc (Target_powerpc::Scan::local): Likewise. Use + is_discarded to flag opd entry as discarded. Don't emit dyn + relocs on such entries. + (Target_powerpc::Scan::global): Similarly detect and handle + such opd entries. + (Powerpc_relobj): Replace opd_ent_shndx_ and opd_ent_off_ with + opd_ent_. Update all uses. + (Powerpc_relobj::get_opd_discard, set_opd_discard): New functions. + (Target_powerpc::relocate_section): Zero out discarded opd + entry relocs. + +2012-09-12 Ian Lance Taylor + + PR gold/14570 + * output.cc: Rename Output_data_got template parameter from size + to got_size for all functions. Compile all variants of + Output_data_got. + (Output_data_got::Got_entry::write): Correct use of size for + symbol value. Use local_is_tls rather than casting to + Sized_relobj_file. + * object.h (class Object): Add local_is_tls and do_local_is_tls. + (class Sized_relobj_file): Add do_local_is_tls. + * incremental.h (class Sized_relobj_incr): Add do_local_is_tls. + +2012-09-11 Alan Modra + + PR gold/14566 + * layout.cc (Layout::set_segment_offsets): When using + common-page-size alignment, ensure we are on a new max-page-size + page. + * output.cc (Output_segment::set_section_addresses): Use + abi_pagesize, not common_pagesize for relro boundary. + (Output_segment::set_offset): Likewise. + +2012-09-11 Alan Modra + + * output.h (Output_data_got::add_global_tls, add_local_tls, + add_local_tls_pair): New functions. + (Output_data_got::add_local_pair_with_rel): Remove second + reloc param. Expand comment. + (Output_data_got::Got_entry): Rename use_plt_offset_ to + use_plt_or_tls_offset_, similarly for constructor param. + (Output_data_got::Got_entry::write): Add got_index param. + * output.cc (Output_data_got::add_global_tls, add_local_tls, + add_local_tls_pair): New functions. + (Output_data_got::Got_entry::write): Handle tls symbols + with use_plt_or_tls_offset_ set specially. + (Output_data_got::add_local_pair_with_rel): Only one reloc. + (Output_data_got::do_write): Replace iterator with index, pass + index to entry write function. + * target.h (Target::tls_offset_for_local, tls_offset_for_global, + do_tls_offset_for_local, do_tls_offset_for_global): New functions. + * arm.cc (Target_arm::Scan::local): Update add_local_pair_with_rel + call. + * i386.cc (Target_i386::Scan::local): Likewise. + * sparc.cc (Target_sparc::Scan::local): Likewise. + * x86_64.cc (Target_x86_64::Scan::local): Likewise. + * powerpc.cc (Target_powerpc::do_tls_offset_for_local, + do_tls_offset_for_global): New functions. + (Target_powerpc::Scan::local): Correct TLS relocations and got + entry values. + (Target_powerpc::Scan::global): Don't emit unnecessary + dynamic relocations on TLS GOT entries. + +2012-09-10 Matthias Klose + + * config.in: Disable sanity check for kfreebsd. + +2012-09-10 Sterling Augustine + + * gdb-index.cc (Gdb_index::pubnames_read): New parameter. + (Gdb_index::pubtypes_read): New parameter. + (Gdb_index_info_reader::read_pubnames_and_pubtypes): Add parameters + to calls. + * gdb-index.h (Gdb_index): New fields pubnames_object_ and + pubtypes_object_. + +2012-09-09 Alan Modra + + * target.h (Target::gc_mark_symbol, do_gc_mark_symbol): New functions. + (Sized_target::gc_add_reference, do_gc_add_reference): New functions. + * gc.h (gc_process_relocs): Call target gc_add_reference. + * gold.cc (queue_middle_tasks): Use gc_mark_symbol on start sym. + * symtab.cc (Symbol_table::gc_mark_undef_symbols): Use gc_mark_symbol. + (Symbol_table::gc_mark_symbol): Call target gc_mark_symbol. Remove + unnecessary cast. + * powerpc.cc (Powerpc_relobj::get_opd_ent): Rearrange parameters + to cater for when we don't need code offset. Update use. + (Powerpc_relobj::access_from_map_, opd_valid_): New vars. + (Powerpc_relobj::access_from_map, add_reference, opd_valid, + set_opd_valid): New functions. + (Target_powerpc::do_gc_add_reference): New function. + (Target_powerpc::gc_process_relocs): Call gc()->add_reference on + stashed refs. + (Target_powerpc::do_gc_mark_symbol): New function. + +2012-09-06 Cary Coutant + + * dwarf_reader.cc (Dwarf_die::read_attributes): Add + DW_FORM_GNU_addr_index and DW_FORM_GNU_str_index. + (Dwarf_die::skip_attributes): Likewise. + * object.cc (Read_symbols_data::~Read_symbols_data): Update comment. + * testsuite/gdb_index_test.cc (inline_func_1): New function. + (main): Call it. + * testsuite/gdb_index_test_comm.sh: Check index for inline function. + +2012-09-05 H.J. Lu + + * testsuite/script_test_3.t: Add .got.plt output section + statement. + * testsuite/script_test_4.t: Likewise. + +2012-09-05 Alan Modra + + * powerpc.cc (Powerpc_relocate_functions): Upcase enum values, + update all uses and lose "enum" when using type. + +2012-09-05 Alan Modra + + * configure.ac (FN_PTRS_IN_SO_WITHOUT_PIC): False for powerpc. + * configure: Regenerate. + * testsuite/Makefile.am (final_layout.stdout): Pass --synthetic to nm. + (plugin_final_layout.stdout): Likewise. + (memory_test): Set page sizes to 0x1000. + * testsuite/Makefile.in: Regenerate. + * testsuite/discard_locals_test.sh: Add FIXME comment. + * testsuite/justsyms_exec.c: Disable function test for powerpc64. + * testsuite/pr14265.t: Add .got output section statement. + * testsuite/script_test_2.t: Likewise. + * testsuite/script_test_3.t: Likewise. + * testsuite/script_test_4.t: Likewise. + * testsuite/script_test_5.t: Likewise. + * testsuite/script_test_6.t: Likewise. + * testsuite/script_test_7.t: Likewise. + * testsuite/script_test_9.t: Likewise. + +2012-09-05 Alan Modra + + * powerpc.cc (Powerpc_relobj::get_opd_ent): Make const. + (Powerpc_relocate_functions::Status): New typedef. + (Target_powerpc::Scan::get_reference_flags): Handle more relocs. + (Target_powerpc::Scan::local): Handle REL64. + (Target_powerpc::Scan::global): Likewise, and dynamic relocs + for REL32 and REL64. + (Target_powerpc::symval_for_branch): New function, extracted from.. + (Target_powerpc::Relocate::relocate): ..here. Correct plt call + checks. Report overflow errors. + +2012-09-05 Alan Modra + + * object.h (Sized_relobj_file::emit_relocs): Delete. + (Sized_relobj_file::emit_relocs_reltype): Delete. + * reloc.cc (Sized_relobj_file::do_relocate_sections): Call target + relocate_relocs for --emit-relocs. + (Sized_relobj_file::emit_relocs, emit_relocs_reltype): Delete. + * output.h: Update comment. + (Output_segment::first_section): New function. + (Output_segment::first_section_load_address): Use first_section. + * output.cc (Output_segment::first_section): New function extracted.. + (Output_segment::first_section_load_address): ..from here. Delete. + * target-reloc.h (relocate_for_relocatable): Rename to relocate_relocs. + * target.h (Sized_target::relocate_for_relocatable): Likewise. + * arm.cc (Target_arm::relocate_for_relocatable): Likewise, and + adjust call to target.h function. + * i386.cc (Target_i386): Likewise. + * sparc.cc (Target_sparc): Likewise. + * x86_64.cc (Target_x86_64): Likewise. + * powerpc.cc (Target_powerpc): Likewise. + (Target_powerpc::Scan::local, global): Handle R_POWERPC_TLS. Ensure + first tls section has section symbol for optimised local dynamic + output relocs. + (Target_powerpc::Relocate::relocate): Correct local dynamic value. + (Target_powerpc::relocate_relocs): Adjust relocs emitted for + optimised tls code. + * testsuite/testfile.cc (Target_test::relocate_for_relocatable): + Rename to relocate_relocs. Update error message. + +2012-09-04 Andreas Schwab + + * powerpc.cc (do_make_elf_object): Allow ET_EXEC files with + --just-symbols. + +2012-08-31 Alan Modra + + * powerpc.cc (Powerpc_relobj): Add and use Address typedef. + (Powerpc_relobj::toc_base_offset): New stub function. + (Target_powerpc): Add tp_offset, dtp_offset. Rename + got_mod_index_offset to tlsld_got_offset. Update all refs. + (Target_powerpc::Relocate::enum skip_tls): New. + (Target_powerpc::call_tls_get_addr_): New var. + (Target_powerpc::is_branch_reloc): Move to file scope. + (Target_powerpc::relocate_tls, optimize_tls_reloc): Delete. + (Target_powerpc::optimize_tls_gd, optimize_tls_ld, optimize_tls_ie): + New functions. + (Target_powerpc::enum Got_type): Delete old values, add new ones. + (powerpc_info): Correct common_pagesize for ppc64. + (at_tls_transform, needs_dynamic_reloc, use_plt_offset): New functions. + (Powerpc_relocate_functions): Add overflow check enums and functions. + Add non-shift version of rela, rela_ua. Delete all rel public + functions. Delete addr16_lo. Add addr64, addr64_u, addr32, + addr32_u, addr24, addr16_u, addr16_hi2, addr16_ha2, addr16_hi3, + addr16_ha3, addr14 functions. + (Output_data_got_powerpc::add_constant_pair): New function. + (Output_data_got_powerpc::got_base_offset): Likewise. + (Output_data_got_powerpc::do_write): Correct 64-bit got header. + (instruction constants): Sort, add some more. + (Output_data_glink::do_write): Add and use Address typedef. Use + object->toc_base_offset() stub for 64-bit. + (Target_powerpc::tlsld_got_offset): Use add_constant_pair. + (Target_powerpc::Scan::get_reference_flags): Handle more relocs. + (Target_powerpc::Scan::local, global): Emit relative dynamic reloc + for R_PPC64_TOC. Handle more relocs. Generate got entries for TLS. + Always treat .opd relocs as against locally defined symbol. + Correct condition for RELATIVE relocs. + (Target_powerpc::do_finalize_sections): Test for NULL sections. + (Target_powerpc::Relocate::relocate): Use plt call stub as value + for 32-bit syms with a plt entry. Correct ppc64 toc base + calculations. Handle TLS relocs, and more. Add overflow + checking and adjust for Powerpc_relocate_functions changes. + (Target_powerpc::relocate_for_relocatable): Handle zero r_sym. + Reinstate --emit-relocs code with FIXME. + +2012-08-30 Alan Modra + + * layout.cc (Layout::set_segment_offsets): Set p_align to + abi_pagesize, not common_pagesize. + (Layout::relaxation_loop_body): Similarly use abi_pagesize + to determine whether file header can go in segment. + +2012-08-30 Alan Modra + + * output.h (Output_reloc::Output_reloc ): Add + is_relative param. Adjust calls. + (Output_reloc::add_output_section_relative): New functions. + * output.cc (Output_reloc::Output_reloc ): Handle + is_relative. + (Output_reloc::symbol_value): Handle SECTION_CODE. + +2012-08-24 Sriraman Tallam + + * gold.cc (queue_middle_tasks): Call layout again when unique + segments for sections is desired. + * layout.cc (Layout::Layout): Initialize new members. + (Layout::get_output_section_flags): New function. + (Layout::choose_output_section): Call get_output_section_flags. + (Layout::layout): Make output section for mapping to a unique segment. + (Layout::insert_section_segment_map): New function. + (Layout::attach_allocated_section_to_segment): Make unique segment for + output sections marked so. + (Layout::segment_precedes): Check for unique segments when sorting. + * layout.h (Layout::Unique_segment_info): New struct. + (Layout::Section_segment_map): New typedef. + (Layout::insert_section_segment_map): New function. + (Layout::get_output_section_flags): New function. + (Layout::is_unique_segment_for_sections_specified): New function. + (Layout::set_unique_segment_for_sections_specified): New function. + (Layout::unique_segment_for_sections_specified_): New member. + (Layout::section_segment_map_): New member. + * object.cc (Sized_relobj_file::do_layout): + Rename is_gc_pass_one to is_pass_one. + Rename is_gc_pass_two to is_pass_two. + Rename is_gc_or_icf to is_two_pass. + Check for which pass based on whether symbols data is present. + Make it two pass when unique segments for sections is desired. + * output.cc (Output_section::Output_section): Initialize new + members. + * output.h (Output_section::is_unique_segment): New function. + (Output_section::set_is_unique_segment): New function. + (Output_section::is_unique_segment_): New member. + (Output_section::extra_segment_flags): New function. + (Output_section::set_extra_segment_flags): New function. + (Output_section::extra_segment_flags_): New member. + (Output_section::segment_alignment): New function. + (Output_section::set_segment_alignment): New function. + (Output_section::segment_alignment_): New member. + (Output_segment::Output_segment): Initialize is_unique_segment_. + (Output_segment::is_unique_segment): New function. + (Output_segment::set_is_unique_segment): New function. + (Output_segment::is_unique_segment_): New member. + * plugin.cc (allow_unique_segment_for_sections): New function. + (unique_segment_for_sections): New function. + (Plugin::load): Add new functions to transfer vector. + * Makefile.am (plugin_final_layout.readelf.stdout): Add readelf output. + * Makefile.in: Regenerate. + * testsuite/plugin_final_layout.sh: Check if unique segment + functionality works. + * testsuite/plugin_section_order.c (onload): Check if new interfaces + are available. + (allow_unique_segment_for_sections): New global. + (unique_segment_for_sections): New global. + (claim_file_hook): Call allow_unique_segment_for_sections. + (all_symbols_read_hook): Call unique_segment_for_sections. + +2012-08-22 Cary Coutant + + * layout.cc (Layout::include_section): Don't assert on GROUP + sections with --emit-relocs. + +2012-08-21 Cary Coutant + + * symtab.cc (Symbol_table::gc_mark_undef_symbols): Don't assert + if --export-dynamic-symbol names an undef symbol. + +2012-08-18 Alan Modra + + * powerpc.cc: Formatting and white space. + (Powerpc_relobj): Rename got2_section_ to special_. + Add opd_ent_shndx_ and opd_ent_off_ vectors. + (Powerpc_relobj::opd_shndx, init_opd, get_opd_ent, set_opd_ent, + scan_opd_relocs, do_read_relocs, opd_ent_ndx): New functions. + (Target_powerpc): Add Address typedef and invalid_address. Use + throughout. + (Target_powerpc::is_branch_reloc): New function. + (Powerpc_relocate_functions): Add Address typedef, use throughout. + (Powerpc_relocate_functions:rela, rela_ua): Correct type used + for dst_mask, value and addend. + (Powerpc_relobj::do_find_special_sections): Find .opd for 64-bit. + (ld_2_1, cror_15_15_15, cror_31_31_31): New insn constants. + (Output_data_glink::do_write): Correct toc base. Don't try to use + uint16_t for 24-bit offset. Use get_output_section_offset and + check return. + (Target_powerpc::Scan::local): Handle more relocs. + (Target_powerpc::do_finalize_sections): Set up DT_PPC64_GLINK. + (Target_powerpc::Relocate::relocate): Correct toc base calculation. + Plug in toc restoring insn after plt calls. Translate branches + to function descriptor symbols to corresponding entry point. + (Target_powerpc::relocate_for_relocatable): Check return from + get_output_section_offset. + * symtab.h: Comment typo. + +2012-08-14 Ian Lance Taylor + + * x86_64.cc (Target_x86_64::Scan::global): Fix erroneous call to + unsupported_relocal_local to call unsupported_reloc_global. + +2012-08-14 Nick Clifton + + PR ld/14265 + * script-sections.cc (Sections_element::output_section_name): Add + keep return parameter. + (Output_section_element::match_name): Add keep return parameter. + Return the value of the keep_ member. + * script-sections.h (class Output_section): Update + output_section_name prototype. + * layout.cc (Layout::keep_input_section): New public member + function. + (Layout::choose_output_section): Pass keep parameter to + output_section_name. + * layout.h (class Layout): Add keep_input_section. + * object.cc (Sized_relobj_file::do_layout): Check for kept input + sections. + * testsuite/Makefile.am: Add a test. + * testsuite/Makefile.in: Regenerate. + * testsuite/pr14265.c: Source file for the test. + * testsuite/pr14265.t: Linker script for the test. + * testsuite/pr14265.sh: Shell script for the test. + +2012-08-14 Alan Modra + + * target.h (Target::output_section_name): New function. + (Target::do_output_section_name): New function. + * layout.cc (Layout::choose_output_section): Call the above. + * powerpc.cc (Target_powerpc::do_output_section_name): New function. + +2012-08-14 Alan Modra + + * powerpc.cc: Update for renamed R_PPC_REL16 relocs. + (Output_data_got_powerpc::do_write): Don't rely on base class lookup + for replace_constant call. + (Output_data_plt_powerpc::do_print_to_mapfile): New function. + (Output_data_glink::do_print_to_mapfile): New function. + (Target_powerpc::Scan::local): Ignore R_PPC64_TOCSAVE. + (Target_powerpc::Relocate::relocate): Likewise. + +2012-08-14 Alan Modra + + * powerpc.cc (Powerpc_relobj::set_got2_shndx): Delete. + (Powerpc_relobj::do_find_special_sections): Don't use set_got2_shndx. + (Output_data_glink::add_entry,find_entry): Remove shndx param. + (class Glink_sym_ent): Rename from struct Glink_sym_ent. Remove + all references to shndx_. Handle special case for R_PPC_PLTREL24 + here. + (class Glink_sym_ent_hash): Rename from struct Glink_sym_ent_hash. + (Output_data_glink::do_write): Retrieve got2_shdnx from object. + (Target_powerpc::make_plt_entry): Don't special case R_PPC_PLTREL24 + here. + (Target_powerpc::Scan::global): Nor on make_plt_entry call. + (Target_powerpc::Relocate::relocate): Nor on glink->find_entry call. + +2012-08-12 Alan Modra + + * powerpc.cc: Whitespace fixes. Wrap overly long lines. + (glink insn constants): Use uint32_t. + (Output_data_glink::add_entry): Use insert, not [] operator. + +2012-08-11 Alan Modra + + * object.h (Sized_relobj_file::find_shdr): New function. + (Sized_relobj_file::find_special_sections): New function. + * object.cc (Sized_relobj_file::find_shdr): New function. + (Sized_relobj_file::find_eh_frame): Use find_shdr. + (Sized_relobj_file::find_special_sections): New function, split out.. + (Sized_relobj_file::do_read_symbols): ..from here. + * output.h (Output_data_got::replace_constant): New function. + (Output_data_got::num_entries): New function. + (Output_data_got::last_got_offset,set_got_size): Use num_entries. + (Output_data_got::got_offset): Protected rather than private. + (Output_data_got::replace_got_entry): New function. + * output.cc (Output_data_got::replace_got_entry): New function. + * powerpc.cc (class Powerpc_relobj): New. + (class Powerpc_relocate_functions): Delete all psymval variants or + convert to value,addend type. Delete pcrela, pcrela_unaligned. + Implement _ha functions using corresponding _hi function. + (Powerpc_relobj::find_special_sections): New function. + (Target_powerpc::do_make_elf_object): New function. + (class Output_data_got_powerpc): New. + (class Output_data_glink): New. + (class Powerpc_scan_relocatable_reloc): New. + Many more changes througout file. + +2012-08-09 Nick Clifton + + * po/vi.po: Updated Vietnamese translation. + +2012-08-07 Ian Lance Taylor + + * layout.cc (Layout::add_target_dynamic_tags): If + dynrel_includes_plt but no dyn_rel, emit dynamic reloc tags for + plt_rel. + +2012-07-30 Nick Clifton + + * po/gold.pot: Updated template. + * po/es.po: Updated Spanish translation. + +2012-07-18 Cary Coutant + + PR gold/14344 + * configure.ac: Add check for -gpubnames support. + * configure: Regenerate. + * testsuite/Makefile.am (gdb_index_test_1): Add check for -gpubnames + support; force -gno-pubnames. + (gdb_index_test_2, gdb_index_test_3): Add check for -gpubnames + support. + (gdb_index_test_4): New test. + * testsuite/Makefile.in: Regenerate. + * testsuite/gdb_index_test_1.sh: Refactor code into common file. + * testsuite/gdb_index_test_2.sh: Likewise. + * testsuite/gdb_index_test_3.sh: Don't look for space after colon. + * testsuite/gdb_index_test_4.sh: New script. + * testsuite/gdb_index_test_comm.sh: New script with common code; + don't look for space after colon. + +2012-07-16 Sriraman Tallam + + * gold.cc (queue_middle_tasks): Update function order only after + deferred objects due to plugins are processed. + +2012-07-11 Ian Lance Taylor + + * arm.cc (Arm_relocate_functions::abs16): Remove unused typedef. + (Arm_exidx_cantunwind::do_fixed_endian_write): Likewise. + (Target_arm::scan_reloc_for_stub): Likewise. + * common.cc (Symbol_table::do_allocate_commons_list): Likewise. + * dwarf_reader.cc (Dwarf_die::skip_attributes): Likewise. + * ehframe.cc (Eh_frame::do_add_ehframe_input_section): Likewise. + * incremental.cc (Sized_incr_dynobj::do_add_symbols): Likewise. + * powerpc.cc (Target_powerpc::relocate_tls): Likewise. + +2012-07-10 Dodji Seketeli + Ian Lance Taylor + + PR gold/14309 + * configure.ac: Test whether std::tr1::hash works. + * gold.h: Add a specialization for std::tr1::hash if + needed. + * output.h (class Output_fill): Add virtual destructor. + * configure, config.in: Rebuild. + +2012-06-22 Roland McGrath + + * layout.cc (finalize): Define __ehdr_start symbol if applicable. + +2012-06-12 Rafael Ávila de Espíndola + + * plugin.cc (Plugin::load): Handle position independent executables. + +2012-06-06 Cary Coutant + + * layout.cc (gdb_sections): Remove ".debug_" prefixes, + add .debug_macro. + (lines_only_debug_sections): Likewise. + (gdb_fast_lookup_sections): New static array. + (is_gdb_debug_section): Rename formal parameter. + (is_lines_only_debug_section): Likewise. + (is_gdb_fast_lookup_section): New function. + (Layout::include_section): Check for ".zdebug_" prefix; pass + section name suffix to is_gdb_debug_section, et al.; check for + fast-lookup sections when building .gdb_index. + * options.h (--strip-debug-gdb): Update GDB version number. + +2012-06-06 Cary Coutant + + * configure.ac: Add check for fallocate. + * configure: Regenerate. + * config.in: Regenerate. + + * options.h (class General_options): Add --mmap-output-file and + --posix-fallocate options. + * output.cc: (posix_fallocate): Remove; replace with... + (gold_fallocate): New function. + (Output_file::map_no_anonymous): Call gold_fallocate. + (Output_file::map): Check --mmap-output-file option. + +2012-06-05 Jing Yu + + * gold.h (textdomain): Add do {} to empty while(0). + (bindtextdomain): Likewise. + +2012-06-04 Cary Coutant + + * dynobj.cc (Sized_dynobj::do_get_global_symbol_counts): Call + has_dynsym_index. + +2012-05-25 Sriraman Tallam + + * symtab.cc (Symbol_table::define_special_symbol): + Initialize *poldsym to prevent uninitialized variable errors. + +2012-05-23 Cary Coutant + + * layout.cc (Layout::section_name_mapping): Add rules to handle + exact match on .data.rel.ro.local or .data.rel.ro. + (Layout::output_section_name): Check for exact matches. + +2012-05-23 Cary Coutant + + * layout.cc (Layout::section_name_mapping): Match .data.rel.ro.* + more carefully. + +2012-05-22 Cary Coutant + + * symtab.cc (Symbol::should_add_dynsym_entry): Check for relocatable + object before exporting symbol. + +2012-05-21 H.J. Lu + + * testsuite/tls_test.cc: Include "config.h" first. + * testsuite/tls_test_c.c: Likewise. + +2012-05-17 Daniel Richard G. + Nick Clifton + + PR 14072 + * configure.in: Add check that sysdep.h has been included before + any system header files. + * configure: Regenerate. + * config.in: Regenerate. + +2012-05-14 Cary Coutant + + * layout.cc (Layout::make_output_section): Mark .tdata section + as RELRO. + * testsuite/relro_test.cc: Add a TLS variable. + +2012-05-10 H.J. Lu + + PR gold/14091 + * x86_64.cc (Target_x86_64::Scan::local): For x32, generate + R_X86_64_RELATIVE64 instead of R_X86_64_RELATIVE in case of + R_X86_64_64. + +2012-05-08 Cary Coutant + + * layout.cc (gdb_sections): Update GDB version, add .debug_addr. + (lines_only_debug_sections): Likewise. + +2012-05-02 Roland McGrath + + * 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 + + * dwarf_reader.cc (Dwarf_die::read_attributes) + (Dwarf_die::skip_attributes, Dwarf_die::int_attribute) + (Dwarf_die::uint_attribute): Remove DW_FORM_null. + * reduced_debug_output.cc + (Output_reduced_debug_info_section::get_die_end): Remove + DW_FORM_GNU_ref_index. Add default case. + +2012-04-26 Mark Wielaard + + * dwarf_reader.cc (Dwarf_die::address_attribute): New function. + * dwarf_reader.h (Dwarf_die::address_attribute): Likewise. + * gdb-index.cc (Gdb_index_info_reader::record_cu_ranges): Handle + DW_AT_high_pc as offset from DW_AT_low_pc. + + * testsuite/Makefile.am (gdb_index_test_3.sh): New test case. + * testsuite/Makefile.in: Regenerate. + * testsuite/gdb_index_test_3.c: New test source file. + * testsuite/gdb_index_test_3.sh: New test source file. + +2012-04-25 Ian Lance Taylor + + * arm.cc (Target_arm::do_is_defined_by_abi): Make sym a const + pointer. + (Stub_addend_reader::operator()): Declare Arm_relocate_functions + as a class, not a struct. + (Target_arm::scan_span_for_cortex_a8_erratum): Likewise. + (Target_arm::apply_cortex_a8_workaround): Likewise. + * gc.h: Declare Reloc_types as a struct, not a class. + * object.h: Declare Symbols_data as a struct. + * reloc.h: Declare Read_relocs_data as a struct. + * target.h: Declare Relocate_info as a struct. + +2012-04-24 David S. Miller + + * sparc.cc (Target_sparc::Relocate::relax_call): New function. + (Target_sparc::Relocate::relocate): Call it for R_SPARC_WDISP30 + and R_SPARC_WPLT30. + +2012-04-24 Cary Coutant + + * incremental-dump.cc (find_input_containing_global): Replace + magic number with symbolic constant. + (dump_incremental_inputs): Update version number. + * incremental.cc (Output_section_incremental_inputs): Update version + number; import symbolic constants from Incremental_inputs_reader. + (Incremental_inputs::create_data_sections): Align relocations + section correctly for 64-bit targets. + (Output_section_incremental_inputs::set_final_data_size): Use symbolic + constants; add padding. + (Output_section_incremental_inputs::write_header): Add assert for + header_size. + (Output_section_incremental_inputs::write_input_files): Add assert + for input_entry_size. + (Output_section_incremental_inputs::write_info_blocks): Add padding; + add assert for object_info_size, input_section_entry_size, + global_sym_entry_size. + * incremental.h (Incremental_inputs_reader): Add symbolic constants + for data structure sizes; use them. + (Incremental_input_entry_reader): Import symbolic constants from + Incremental_inputs_reader; use them. + +2012-04-23 David S. Miller + + * sparc.cc (class Target_sparc): Add elf_machine_, elf_flags_, + and elf_flags_set_. + (Target_sparc::Target_sparc): Initialize new fields. + (Target_sparc::do_make_elf_object): New function. + (Target_sparc::do_adjust_elf_header): New function. + +2012-04-23 Cary Coutant + + * gdb-index.cc (Gdb_index::do_write): Use Swap_aligned32 for writing + CU range table of gdb index. + +2012-04-20 David S. Miller + + * target.cc (Sized_target::do_adjust_elf_header): Use big_endian + instead of false. + +2012-04-16 David S. Miller + + * sparc.cc (Target_sparc::got_address): New function. + (Sparc_relocate_functions::gdop_hix22): New function. + (Sparc_relocate_functions::gdop_lox10): New function. + (Target_sparc::Scan::local): Do not emit a GOT entry for GOTDATA + relocs. + (Target_sparc::Scan::local): Likewise if the global symbol is not + preemptible and is not IFUNC. + (Target_sparc::Relocate::relocate): Perform GOTDATA code + transformations for local and non-preemptible non-IFUNC global + symbols. + + * gdb-index.cc (Gdb_index::do_write): Use Swap_unaligned when + writing out 64-bit part of ranges. + + * Makefile.am: Build IFUNC tests with -fPIC and -fPIE instead of + -fpic and -fpie respectively. + * Makefile.in: Regenerate. + + * sparc.cc (class Target_sparc): Add rela_ifunc_. + (Target_sparc::Target_sparc): Initialize new field. + (Target_sparc::do_plt_section_for_global): New function. + (Target_sparc::do_plt_section_for_local): New function. + (Target_sparc::reloc_needs_plt_for_ifunc): New function. + (Target_sparc::make_plt_section): New function, broken out of + make_plt_entry. Use ORDER_NON_RELRO_FIRST for ".plt". + (Target_sparc::make_plt_entry): Call make_plt_section. + (Target_sparc::make_local_ifunc_plt_entry): New function. + (Target_sparc::rela_ifunc_section): New function. + (Target_sparc::plt_section): Remove const. + (Output_data_plt_sparc): Update declarations. Define Global_ifunc + and Local_ifunc types. Add global_ifuncs_, local_ifuncs_, ifunc_rel_, + and ifunc_count_ fields. + (Output_data_plt_sparc::Output_data_plt_sparc): Initialize new fields. + (Output_data_plt_sparc::add_entry): Handle IFUNC symbols. + (Output_data_plt_sparc::add_local_ifunc_entry): New function. + (Output_data_plt_sparc::rela_ifunc): New function. + (Output_data_plt_sparc::emit_pending_ifunc_relocs): New function. + (Output_data_plt_sparc::has_ifunc_section): New function. + (Output_data_plt_sparc::entry_count): Include ifunc_count_. + (Output_data_plt_sparc::address_for_global): New function. + (Output_data_plt_sparc::address_for_local): New function. + (Output_data_plt_sparc::plt_index_to_offset): New function. + (Output_data_plt_sparc::set_final_data_size): Use plt_index_to_offset + and entry_count. + (Output_data_plt_sparc::do_write): Use first_plt_entry_offset and + entry_count. + (Target_sparc::Scan::get_reference_flags): Add R_SPARC_IRELATIVE and + R_SPARC_JMP_IREL to switch. + (Target_sparc::Scan::check_non_pic): Likewise. + (Target_sparc::Scan::local): Handle IFUNC symbols. + (Target_sparc::Scan::local): Likewise. + (Target_sparc::Relocate::relocate): Likewise, use plt_address_for_global + and plt_address_for_local. + (Target_sparc::do_finalize_sections): Call emit_pending_ifunc_relocs. + Define __rel_iplt_start and __rel_iplt_end if doing a static link. + + * output.h (Output_reloc): Allow use_plt_offset for global relocs too. + (class Output_data_reloc): Adjust calls to Output_reloc_type. + (Output_data_reloc::add_global_relative): (RELA only) Add use_plt_offset. + * output.cc (Output_reloc::Output_reloc): Add use_plt_offset flag for + global relocs too. + (Output_reloc::symbol_value): Respect use_plt_offset_ for global symbols. + * powerpc.cc (Target_powerpc::Scan::global): Adjust add_global_relative + calls. + * sparc.cc (Target_sparc::Scan::global): Likewise. + * x86_64.cc (Target_x86_64::Scan::global): Likewise. + +2012-04-16 Cary Coutant + + * archive.cc (Library_base::should_include_member): Check for + --export-dynamic-symbol. + * options.h (class General_options): Add --export-dynamic-symbol. + * symtab.cc (Symbol::should_add_dynsym_entry): Check for + --export-dynamic-symbol. + (Symbol_table::gc_mark_undef_symbols): Likewise. + (Symbol_table::do_add_undefined_symbols_from_command_line): Likewise. + +2012-04-12 David S. Miller + + * sparc.cc (Reloc::wdisp10): New relocation method. + (Reloc::h34): Likewise. + (Target_sparc::Scan::check_non_pic): Handle R_SPARC_H34. + (Target_sparc::Scan::get_reference_flags): Handle R_SPARC_H34 and + R_SPARC_WDISP10. + (Target_sparc::Scan::local): Likewise. + (Target_sparc::Scan::global): Likewise. + (Target_sparc::Relocate::relocate): Likewise. + +2012-04-09 Cary Coutant + + * gdb-index.cc (Gdb_index_info_reader::record_cu_ranges): Allow + low_pc == 0. + +2012-04-06 Ian Lance Taylor + + * timer.cc: #include . + +2012-04-06 Roland McGrath + + * configure.in (AC_CHECK_HEADERS): Add locale.h. + * config.in: Regenerate. + * configure: Regenerate. + +2012-04-05 Nick Clifton + + * configure.ac (AC_CHECK_FUNCS): Add setlocale. + (AM_LC_MESSAGES): Add. + * aclocal.m4: Regenerate. + * config.in: Regenerate. + * configure: Regenerate. + +2012-03-21 Cary Coutant + + * Makefile.am: Add gdb-index.cc, gdb-index.h. + * Makefile.in: Regenerate. + * dwarf_reader.cc (Sized_elf_reloc_mapper::do_initialize): New function. + (Sized_elf_reloc_mapper::symbol_section): New function. + (Sized_elf_reloc_mapper::do_get_reloc_target): New function. + (make_elf_reloc_mapper): New function. + (Dwarf_abbrev_table::clear_abbrev_codes): New function. + (Dwarf_abbrev_table::do_read_abbrevs): New function. + (Dwarf_abbrev_table::do_get_abbrev): New function. + (Dwarf_ranges_table::read_ranges_table): New function. + (Dwarf_ranges_table::read_range_list): New function. + (Dwarf_pubnames_table::read_section): New function. + (Dwarf_pubnames_table::read_header): New function. + (Dwarf_pubnames_table::next_name): New function. + (Dwarf_die::Dwarf_die): New function. + (Dwarf_die::read_attributes): New function. + (Dwarf_die::skip_attributes): New function. + (Dwarf_die::set_name): New function. + (Dwarf_die::set_linkage_name): New function. + (Dwarf_die::attribute): New function. + (Dwarf_die::string_attribute): New function. + (Dwarf_die::int_attribute): New function. + (Dwarf_die::uint_attribute): New function. + (Dwarf_die::ref_attribute): New function. + (Dwarf_die::child_offset): New function. + (Dwarf_die::sibling_offset): New function. + (Dwarf_info_reader::check_buffer): New function. + (Dwarf_info_reader::parse): New function. + (Dwarf_info_reader::do_parse): New function. + (Dwarf_info_reader::do_read_string_table): New function. + (Dwarf_info_reader::lookup_reloc): New function. + (Dwarf_info_reader::get_string): New function. + (Dwarf_info_reader::visit_compilation_unit): New function. + (Dwarf_info_reader::visit_type_unit): New function. + (Sized_dwarf_line_info::Sized_dwarf_line_info): Use + Sized_elf_reloc_mapper. + (Sized_dwarf_line_info::symbol_section): Remove function. + (Sized_dwarf_line_info::read_relocs): Use Sized_elf_reloc_mapper. + (Sized_dwarf_line_info::read_line_mappings): Remove object + parameter, adjust callers. + (Sized_dwarf_line_info::format_file_lineno): Fix type of cast. + * dwarf_reader.h: Include . + (class Track_relocs): Remove forward declaration. + (class Elf_reloc_mapper): New class. + (class Sized_elf_reloc_mapper): New class. + (class Dwarf_abbrev_table): New class. + (class Dwarf_range_list): New class. + (class Dwarf_ranges_table): New class. + (class Dwarf_pubnames_table): New class. + (class Dwarf_die): New class. + (class Dwarf_info_reader): New class. + (Sized_dwarf_line_info::read_line_mappings): Remove object parameter. + (Sized_dwarf_line_info::symbol_section): Remove member function. + * dynobj.h (Sized_dynobj::do_section_contents): Refactor code from + base class. + * gdb-index.cc: New source file. + * gdb-index.h: New source file. + * incremental.cc (Sized_relobj_incr::do_layout): Track .debug_info + and .debug_types sections, call Layout::add_to_gdb_index. + (Sized_relobj_incr::do_section_name): Implement. + (Sized_relobj_incr::do_section_contents): Adjust parameter list and + return type; Implement. + (Sized_incr_dynobj::do_section_contents): Adjust parameter list and + return type. + * incremental.h (Sized_relobj_incr::do_section_contents): Adjust + parameter list and return type. + (Sized_incr_dynobj::do_section_contents): Likewise. + * layout.cc: Include gdb-index.h. + (Layout::Layout): Initialize gdb_index_data_. + (Layout::init_fixed_output_section): Check for .gdb_index section. + (Layout::add_to_gdb_index): New function. Instantiate. + * layout.h: Add forward declaration for class Gdb_index. + (Layout::add_to_gdb_index): New member function. + (Layout::gdb_index_data_): New data member. + * main.cc: Include gdb-index.h. + (main): Print statistics for gdb index. + * object.cc (Object::section_contents): Move code into + do_section_contents. + (need_decompressed_section): Check for sections needed when building + gdb index. + (build_compressed_section_map): Likewise. + (Sized_relobj_file::do_read_symbols): Need local symbols when building + gdb index. + (Sized_relobj_file::do_layout): Track .debug_info and .debug_types + sections; call Layout::add_to_gdb_index. + (Sized_relobj_file::do_decompressed_section_contents): Call + do_section_contents directly. + * object.h (Object::do_section_contents): Adjust parameter list and + return type. + (Object::do_decompressed_section_contents): Call do_section_contents + directly. + (Sized_relobj_file::do_section_contents): Adjust parameter list and + return type. + * options.h (class General_options): Add --gdb-index option. + * plugin.cc (Sized_pluginobj::do_section_contents): Adjust parameter + list and return type. + * plugin.h (Sized_pluginobj::do_section_contents): Likewise. + * reloc.h (Track_relocs::checkpoint): New function. + (Track_relocs::reset): New function. + + * testsuite/Makefile.am (gdb_index_test_1.sh, gdb_index_test_2.sh): + New test cases. + * testsuite/Makefile.in: Regenerate. + * testsuite/gdb_index_test.cc: New test source file. + * testsuite/gdb_index_test_1.sh: New test source file. + * testsuite/gdb_index_test_2.sh: New test source file. + +2012-03-19 Doug Kwan + + * arm.cc (Target_arm::do_define_standard_symbols): New method. + (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 + target-specific symbols. + * target.h (Target::define_standard_symbols): New method. + (Target::do_define_standard_symbols): Same. + * testsuite/Makefile.am (arm_exidx_test): Dump relocations also. + * testsuite/Makefile.in: Regenerate. + * testsuite/arm_exidx.s: Generate data relocations for __exidx_start + and __exidx_end. + * testsuite/arm_exidx_test.sh: Check that no unused dynamic + relocations are generated for __exidx_start and __exidx_end. + +2012-03-16 Doug Kwan + + * testsuite/Makefile.am: Disable test initpri3b. + * testsuite/Makefile.in: Regenerate. + +2012-03-15 Doug Kwan + + * arm.cc (Target_arm::got_section): Make .got section read-only + if -z now is given. + +2012-03-15 Ian Lance Taylor + + PR gold/13850 + * layout.cc (Layout::make_output_section): Correctly mark + SHT_INIT_ARRAY, et. al., as relro. + +2012-03-14 Doug Kwan + + * gold/arm.cc (Target_arm::Scan::global): Generate R_ARM_GLOB_DAT + dynamic relocations for protected symbols in shared objects. + +2012-03-13 Ian Lance Taylor + + * resolve.cc (Symbol_table::resolve): When merging common symbols, + keep the larger alignment. + +2012-03-12 Cary Coutant + + * dwarf_reader.cc (Sized_dwarf_line_info::process_one_opcode): Fix + handling of DW_LNE_define_file. + +2012-03-12 Cary Coutant + + * reduced_debug_output.cc + (Output_reduced_debug_info_section::get_die_end): Add new FORM + codes to switch. + +2012-02-29 Cary Coutant + + * object.cc (need_decompressed_section): Add #ifdef ENABLE_THREADS. + +2012-02-29 Cary Coutant + + * dwarf_reader.cc (Sized_dwarf_line_info::Sized_dwarf_line_info): + Call Object::decompressed_section_contents. + * dwarf_reader.h (Sized_dwarf_line_info::~Sized_dwarf_line_info): + New dtor. + (Sized_dwarf_line_info::buffer_start_): New data member. + * merge.cc (Output_merge_data::do_add_input_section): Call + Object::decompressed_section_contents. + (Output_merge_string::do_add_input_section): Likewise. + * object.cc (need_decompressed_section): New function. + (build_compressed_section_map): Decompress sections needed later. + (Sized_relobj_file::do_decompressed_section_contents): New function. + (Sized_relobj_file::do_discard_decompressed_sections): New function. + * object.h (Object::decompressed_section_contents): New function. + (Object::discard_decompressed_sections): New function. + (Object::do_decompressed_section_contents): New function. + (Object::do_discard_decompressed_sections): New function. + (Compressed_section_info): New type. + (Compressed_section_map): Include decompressed section contents. + (Sized_relobj_file::do_decompressed_section_contents): New function. + (Sized_relobj_file::do_discard_decompressed_sections): New function. + +2012-02-16 Cary Coutant + + * testsuite/Makefile.am (initpri2): Add --ctors-in-init-array option. + * testsuite/Makefile.in: Regenerate. + +2012-02-14 Cary Coutant + + * options.cc (General_options::finalize): Disallow -pie and -static. + +2012-02-03 Doug Kwan + + * arm.cc (Arm_relocate_functions::abs8, + Arm_relocate_functions::abs16): Use + Bits::has_signed_unsigned_overflow32. + (Arm_relocate_functions::thm_abs8): Correct range of + overflow check. + * reloc.h (Bits class): Change minimum number of bits from 0 to 1 + in assertions. + +2012-02-02 Doug Kwan + + * arm.cc (Reloc_stub::stub_type_for_reloc): Use PIC stubs in all + position independent outputs, not just shared objects. + +2012-01-30 H.J. Lu + + * configure.ac: Check if -fpic -mtls-dialect=gnu2 works. + * configure: Regenerated. + +2012-01-27 Ian Lance Taylor + + * reloc.h (Bits): New class with static functions, copied from + namespace utils in arm.cc. + * arm.cc (namespace utils): Remove. Rewrite all uses to use Bits + instead. + +2012-01-27 H.J. Lu + + * incremental.cc (write_info_blocks): Correct relocation offset. + +2012-01-27 H.J. Lu + + * x86_64.cc (Relocate::tls_gd_to_ie): Support x32. + (Relocate::tls_gd_to_le): Likewise. + +2012-01-27 H.J. Lu + + * x86_64.cc (Scan::global): Support x32 IFUNC function pointer. + +2012-01-27 H.J. Lu + + * configure.ac: Check if -mcmodel=medium works. + * configure: Regenerated. + +2012-01-24 Cary Coutant + + * int_encoding.cc (read_unsigned_LEB_128): Replaced with inline + definition and ... + (read_unsigned_LEB_128_x): ... this new function. + (read_signed_LEB_128): Replaced with inline definition and ... + (read_signed_LEB_128_x): ... this new function. + * int_encoding.h (read_unsigned_LEB_128_x): New function. + (read_unsigned_LEB_128): Add inline definition. + (read_signed_LEB_128_x): New function. + (read_signed_LEB_128): Add inline definition. + * testsuite/Makefile.am (leb128_unittest): New unit test. + * testsuite/Makefile.in: Regenerate. + * testsuite/leb128_unittest.cc: New unit test. + +2012-01-23 Ian Lance Taylor + + PR gold/13617 + * i386.cc (Target_i386::do_code_fill): When using a jmp + instruction, pad with nop instructions. + * x86_64.cc (Target_x86_64::do_code_fill): Likewise. + +2012-01-22 H.J. Lu + + * x86_64.cc (gc_process_relocs): Add typename on types used in + template. + (scan_relocs): Likewise. + (relocate_section): Likewise. + (apply_relocation): Likewise. + +2012-01-10 H.J. Lu + + * x86_64.cc (Scan::check_non_pic): Allow R_X86_64_32 for x32. + (Scan::local): Use R_X86_64_RELATIVE relocation for R_X86_64_32 + under x32. + +2012-01-09 H.J. Lu + + * x86_64.cc: Initial support for x32. + +2012-01-03 Cary Coutant + + * gold/incremental.cc (Sized_incremental_binary::do_process_got_plt): + Use abstract base class for GOT. + * gold/output.h (class Output_data_got_base): New abstract base class. + (class Output_data_got): Derive from new base class, adjust ctors. + (Output_data_got::reserve_slot): Make virtual; rename to + do_reserve_slot; Adjust callers. + * gold/target.h (Sized_target::init_got_plt_for_update): Return + pointer to abstract base class. + * gold/x86_64.cc (Target_x86_64::init_got_plt_for_update): Likewise. + +2011-12-18 Ian Lance Taylor + + * object.h (Relobj::local_symbol_value): New function. + (Relobj::local_plt_offset): New function. + (Relobj::local_has_got_offset): New function. + (Relobj::local_got_offset): New function. + (Relobj::set_local_got_offset): New function. + (Relobj::do_local_symbol_value): New pure virtual function. + (Relobj::do_local_plt_offset): Likewise. + (Relobj::do_local_has_got_offset): Likewise. + (Relobj::do_local_got_offset): Likewise. + (Relobj::do_set_local_got_offset): Likewise. + (Sized_relobj::do_local_has_got_offset): Rename from + local_has_got_offset. + (Sized_relobj::do_local_got_offset): Rename from local_got_offset. + (Sized_relobj::do_set_local_got_offset): Rename from + set_local_got_offset. + (Sized_relobj_file::do_local_plt_offset): Rename from + local_plt_offset. + (Sized_relobj_file::do_local_symbol_value): New function. + * object.cc (Sized_relobj_file::do_local_plt_offset): Rename from + local_plt_offset. + * output.cc (Output_data_got::Got_entry::write): Change object to + Relobj. Use local_symbol_value. + (Output_data_got::add_global_with_rel): Change rel_dyn to + Output_data_reloc_generic*. Use add_global_generic. + (Output_data_got::add_global_with_rela): Remove. Change all + callers to use add_global_with_rel. + (Output_data_got::add_global_pair_with_rel): Change rel_dyn to + Output_data_reloc_generic*. Use add_global_generic. + (Output_data_got::add_global_pair_with_rela): Remove. Change all + callers to use add_global_pair_with_rel. + (Output_data_got::add_local): Change object to Relobj*. + (Output_data_got::add_local_plt): Likewise. + (Output_data_got::add_local_with_rel): Change object to Relobj*, + change rel_dyn to Output_data_reloc_generic*. Use + add_local_generic. + (Output_data_got::add_local_with_rela): Remove. Change all + callers to use all_local_with_rel. + (Output_data_got::add_local_pair_with_rel): Change object to + Relobj*, change rel_dyn to Output_data_reloc_generic*. Use + add_output_section_generic. + (Output_data_got::add_local_pair_with_rela): Remove. Change all + callers to use add_local_pair_with_rel. + (Output_data_got::reserve_local): Change object to Relobj*. + * output.h: (class Output_data_reloc_generic): Add pure virtual + declarations for add_global_generic, add_local_generic, + add_output_section_generic. + (class Output_data_reloc) [SHT_REL, SHT_RELA]: Implement new + functions for Output_data_reloc_generic. Update declarations for + changes listed in output.cc. + (class Output_data_got): Change template parameter to got_size. + Don't define Rel_dyn or Rela_dyn. Update declarations per above. + * incremental.h (Sized_relobj_incr::do_local_symbol_value): New + function. + (Sized_relobj_incr::do_local_plt_offset): New function. + * copy-relocs.cc (Copy_relocs::Copy_reloc_entry::emit): Call + add_global_generic. + +2011-12-17 Cary Coutant + + * dwarf_reader.cc (Sized_dwarf_line_info::read_lines): Add casts. + * resolve.cc (Symbol_table::resolve): Likewise. + * i386.cc (Target_i386::do_code_fill): Use char constants for nop + arrays. + * x86_64.cc (Target_x86_64::do_code_fill): Likewise. + +2011-12-16 Ian Lance Taylor + + * output.h (Output_data_reloc_generic::add): Only call + add_dynamic_reloc if this is a dynamic reloc section. + +2011-12-15 H.J. Lu + + PR gold/13505 + * target-reloc.h (apply_relocation): Replace <64, false> with + . + +2011-11-25 Nick Clifton + + * po/it.po: New Italian translation. + +2011-11-17 Sterling Augustine + + * script.cc (script_include_directive): Implement. + (read_script_file): New local variables name and search_path. Update + comment. Call IS_ABSOLUTE_PATH and Dirsearch::find_file_in_dir_list. + * dirsearch.h (Dirsearch::find_file_in_dir_list): Declare new method. + * dirsearch.cc (Dirsearch::find_file_in_dir_list): Implement it. + +2011-11-11 Sterling Augustine + + * yyscript.y (section_cmd): Add support for INCLUDE directive. + (file_or_sections_cmd): Likewise. + +2011-11-11 Doug Kwan + + * arm.cc (Target_arm::do_make_elf_object): Allow executable also + if --just-symbols is given. + +2011-11-10 Doug Kwan + + PR gold/13362 + * arm.cc (Target_arm::Relocate::relocate_tls): Do unaligned accesses + when processing data relocs. + * reloc.h (Relocate_functions::rel_unaligned): New method. + (Relocate_functions::pcrel_unaligned): Ditto. + (Relocate_functions::rel32_unaligned): Ditto. + (Relocate_functions::pcrel32_unaligned): Ditto. + +2011-11-09 Doug Kwan + + PR gold/13362 + * arm.cc (Arm_scan_relocatable_relocs::Default_scan_relocatable_relocs): + Use unaligned 4-byte relocs for static 32-bit data as required by EABI. + * reloc.h (Relocatable_relocs::Reloc_strategy): New enum + RELOC_ADJUST_FOR_SECTION_4_UNALIGNED. + (Relocate_functions::rel_unaligned): New. + (Relocate_functions::rel32_unaligned): New. + * target-reloc.h (relocate_for_relocatable): Add code to handle + RELOC_ADJUST_FOR_SECTION_4_UNALIGNED. + * testsuite/Makefile.am (arm_unaligned_reloc_r.stdout, + arm_unaligned_reloc_r): New targets. + * testsuite/Makefile.in: Regenerate. + * arm_unaligned_reloc.sh: Check unaligned relocs in relocatable + linking. + +2011-11-02 Ian Lance Taylor + + * configure.ac: Add --with-lib-path option. Define LIB_PATH and + NATIVE_LINKER. + * Makefile.am (AM_CPPFLAGS): Define TOOLLIBDIR. + * options.cc (General_options::finalize): Use library search path + from configure script if specified. If not native and no sysroot, + only search TOOLLIBDIR. + * options.h (Search_directory::Search_directory): Change name to + const std::string&. + (General_options::add_to_library_path_with_sysroot): Change arg to + const std::string&. + * configure, Makefile.in, config.in: Rebuild. + +2011-11-02 Matthew Gretton-Dann + + * arm.cc (Target_arm::may_use_v5t_interworking): Check whether + we are working around the ARM1176 Erratum. + * options.h (General_options::fix_arm1176): Add option. + * testsuite/Makefile.am: Add testcases, and keep current ones + working. + * testsuite/Makefile.in: Regenerate. + * testsuite/arm_fix_1176.s: New file. + * testsuite/arm_fix_1176.sh: Likewise. + +2011-11-02 Matthew Gretton-Dann + + * arm.cc (Target_arm::Target_arm): Remove initialisation of + may_use_blx_. + (Target_arm::may_use_blx): Remove method. + (Target_arm::set_may_use_blx): Likewise. + (Target_arm::may_use_v4t_interworking): New method. + (Target_arm::may_use_v5t_interworking): Likewise. + (Target_arm::may_use_blx_): Remove member variable. + (Arm_relocate_functions::arm_branch_common): Check for v5T + interworking. + (Arm_relocate_functions::thumb_branch_common): Likewise. + (Reloc_stub::stub_type_for_reloc): Likewise. + (Target_arm::do_finalize_sections): Correct interworking checks. + * testsuite/Makefile.am: Add new tests. + * testsuite/Makefile.in: Regenerate. + * testsuite/arm_farcall_arm_arm.s: New test. + * testsuite/arm_farcall_arm_arm.sh: Likewise. + * testsuite/arm_farcall_arm_thumb.s: Likewise. + * testsuite/arm_farcall_arm_thumb.sh: Likewise. + * testsuite/arm_farcall_thumb_arm.s: Likewise. + * testsuite/arm_farcall_thumb_arm.sh: Likewise. + * testsuite/arm_farcall_thumb_thumb.s: Likewise. + * testsuite/arm_farcall_thumb_thumb.sh: Likewise. + +2011-10-31 Cary Coutant + + PR gold/13023 + * expression.cc (Expression::eval_with_dot): Add + is_section_dot_assignment parameter. + (Expression::eval_maybe_dot): Likewise. Adjust value when rhs is + absolute and assigning to dot within a section. + * script-sections.cc + (Output_section_element_assignment::set_section_addresses): Pass + dot_section to set_if_absolute. + (Output_section_element_dot_assignment::finalize_symbols): Pass TRUE + as is_section_dot_assignment flag to eval_with_dot. + (Output_section_element_dot_assignment::set_section_addresses): + Likewise. + * script.cc (Symbol_assignment::set_if_absolute): Add dot_section + parameter. Also set value if relative to dot_section; set the + symbol's output_section. + * script.h (Expression::eval_with_dot): Add is_section_dot_assignment + parameter. Adjust all callers. + (Expression::eval_maybe_dot): Likewise. + (Symbol_assignment::set_if_absolute): Add dot_section parameter. + Adjust all callers. + * testsuite/script_test_2.t: Test assignment of an absolute value + to dot within an output section element. + +2011-10-31 Cary Coutant + + * options.h (class General_options): Add --[no-]gnu-unique options. + * symtab.cc (Symbol_table::sized_write_globals): Convert + STB_GNU_UNIQUE to STB_GLOBAL if --no-gnu-unique. + +2011-10-31 Cary Coutant + + PR gold/13359 + * i386.cc (Target_i386::Relocate::relocate_tls): Remove + unnecessary assertion. + * x86_64.cc (Target_x86_64::Relocate::relocate_tls): Likewise. + +2011-10-31 Sriraman Tallam + + * symtab.h (Symbol_table::gc_mark_symbol_for_shlib): Rename to + gc_mark_symbol. + * symtab.cc (Symbol_table::gc_mark_symbol_for_shlib): Rename to + gc_mark_symbol. + Change to just keep the section associated with symbol. + (Symbol_table::add_from_relobj): Mark symbols as not garbage when + they are externally visible and --export-dynamic is turned on. + (Symbol_table::gc_mark_dyn_syms): Call gc_mark_symbol. + +2011-10-19 Ian Lance Taylor + + PR gold/13163 + * script-sections.cc + (Output_section_element_dot_assignment::needs_output_section): New + function. + +2011-10-19 Ian Lance Taylor + + PR gold/13204 + * layout.cc (Layout::segment_precedes): Don't assert failure if a + --section-start option was seen. + * options.h (General_options::any_section_start): New function. + +2011-10-18 David S. Miller + + PR binutils/13301 + * sparc.cc (Target_sparc::Relocate::reloc_adjust_addr_): New + member to track relocation locations that have moved during TLS + reloc optimizations. + (Target_sparc::Relocate::Relocate): Initialize to NULL. + (Target_sparc::Relocate::relocate): Adjust view down by 4 + bytes if it matches reloc_adjust_addr_. + (Target_sparc::Relocate::relocate_tls): Always move the + __tls_get_addr call delay slot instruction forward 4 bytes when + performing relaxation. + +2011-10-18 Cary Coutant + + * output.cc (posix_fallocate): Return 0 on success, errno on failure. + (Output_file::map_no_anonymous): Check for non-zero + return code from posix_fallocate. + +2011-10-17 Cary Coutant + + PR gold/13245 + * plugin.cc (is_visible_from_outside): Check for symbols + referenced from dynamic objects. + * resolve.cc (Symbol_table::resolve): Don't count references + from dynamic objects as references from real ELF files. + * testsuite/plugin_test_2.sh: Adjust expected result. + +2011-10-17 Cary Coutant + + * gold.cc: Include timer.h. + (queue_middle_tasks): Stamp time. + (queue_final_tasks): Likewise. + * main.cc (main): Store timer in parameters. Print timers + for each pass. + * parameters.cc (Parameters::Parameters): Initialize timer_. + (Parameters::set_timer): New function. + (set_parameters_timer): New function. + * parameters.h (Parameters::set_timer): New function. + (Parameters::timer): New function. + (Parameters::timer_): New data member. + (set_parameters_timer): New function. + * timer.cc (Timer::stamp): New function. + (Timer::get_pass_time): New function. + * timer.h (Timer::stamp): New function. + (Timer::get_pass_time): New function. + (Timer::pass_times_): New data member. + +2011-10-17 Cary Coutant + + * readsyms.cc (Read_symbols::run): Don't queue an unblocker + task for members of lib groups. + +2011-10-17 Cary Coutant + + PR gold/13288 + * fileread.cc (File_read::find_view): Add assert. + (File_read::make_view): Move bounds check (replace with assert)... + (File_read::find_or_make_view): ... to here. + +2011-10-12 Cary Coutant + + * output.cc (Output_file::open_base_file): Handle case where + ::read returns less than requested size. + +2011-10-10 Cary Coutant + + * incremental.cc (Sized_relobj_incr::Sized_relobj_incr): + Initialize defined_count_. + (Sized_relobj_incr::do_add_symbols): Count defined symbols. + (Sized_relobj_incr::do_get_global_symbol_counts): Rewrite. + (Sized_incr_dynobj::Sized_incr_dynobj): Initialize defined_count_. + (Sized_incr_dynobj::do_add_symbols): Count defined symbols. + (Sized_incr_dynobj::do_get_global_symbol_counts): Rewrite. + * incremental.h (Sized_relobj_incr::defined_count_): New data + member. + (Sized_incr_dynobj::defined_count_): New data member. + * plugin.cc (Sized_pluginobj::do_get_global_symbol_counts): + Return zeroes instead of internal error. + +2011-10-10 Cary Coutant + + PR gold/13249 + * output.cc (Output_reloc::Output_reloc): Add use_plt_offset flag. + (Output_reloc::symbol_value): Return PLT offset if flag is set. + * output.h (class Output_reloc): Add use_plt_offset flag. + (Output_reloc::type_): Adjust size of bit field. + (Output_reloc::use_plt_offset_): New bit field. + (class Output_data_reloc): Adjust all calls to Output_reloc_type. + (Output_data_reloc::add_local_relative): (RELA only) Add use_plt_offset + flag. Adjust all callers. + * x86_64.cc (Target_x86_64::Scan::local): Check for IFUNC when + creating RELATIVE relocations. + +2011-10-10 Nick Clifton + + * po/es.po: Updated Spanish translation. + * po/fi.po: Updated Finnish translation. + +2011-10-03 Diego Novillo + + * options.cc (parse_uint): Fix dereference of RETVAL. + +2011-09-29 Sriraman Tallam + + * layout.h (section_order_map_): New member. + (get_section_order_map): New member function. + * output.cc (Output_section::add_input_section): Check for patterns + only when --section-ordering-file is specified. + * gold.cc (queue_middle_tasks): Delay updating order of sections till + output_sections have been formed. + * layout.cc (Layout_Layout): Initialize section_order_map_. + * plugin.cc (update_section_order): Store order in order_map. Do not + update the order. + * testsuite/Makefile.am: Add test case for plugin_final_layout. + * testsuite/Makefile.in: Regenerate. + * testsuite/plugin_section_order.c: New file. + * testsuite/plugin_final_layout.cc: New file. + * testsuite/plugin_final_layout.sh: New file. + +2011-09-29 Cary Coutant + + * incremental.cc (Sized_incremental_binary::do_process_got_plt): + Check for NULL. + * symtab.cc (Symbol_table::add_from_relobj): Ignore version + symbols during incremental update. + (Symbol_table::add_from_dynobj): Likewise. + +2011-09-27 Viktor Kutuzov + Ian Lance Taylor + + * symtab.cc (Symbol_table::define_special_symbol): Always + canonicalize version string. + +2011-09-26 Cary Coutant + + * gold.cc (queue_initial_tasks): Move option checks ... + * options.cc (General_options::finalize): ... to here. Disable + some options; make others fatal. + +2011-09-26 Cary Coutant + + gcc PR lto/47247 + * plugin.cc (get_symbols_v2): New function. + (Plugin::load): Add LDPT_GET_SYMBOLS_V2. + (is_referenced_from_outside): New function. + (Pluginobj::get_symbol_resolution_info): Add version parameter, return + LDPR_PREVAILING_DEF_IRONLY_EXP when using new version. + (get_symbols): Pass version parameter. + (get_symbols_v2): New function. + * plugin.h (Pluginobj::get_symbol_resolution_info): Add version + parameter. + * testsuite/plugin_test.c (get_symbols_v2): New static variable. + (onload): Add LDPT_GET_SYMBOLS_V2. + (all_symbols_read_hook): Use get_symbols_v2; check for + LDPR_PREVAILING_DEF_IRONLY_EXP. + * testsuite/plugin_test_3.sh: Update expected results. + +2011-09-23 Simon Baldwin + + * configure.ac: Add new --with-gold-ldadd and --with-gold-ldflags + configuration options. + * configure: Regenerate. + * Makefile.am: Handle GOLD_LDADD and GOLD_LDFLAGS. + * Makefile.in: Regenerate. + * testsuite/Makefile.in: Regenerate. + +2011-09-19 Sriraman Tallam + + * plugin.h (should_defer_layout): Modify to check for any_claimed_. + +2011-09-19 Cary Coutant + + * incremental.cc (can_incremental_update): Fix typo in comment. + * incremental.h (can_incremental_update): Likewise. + +2011-09-18 Cary Coutant + + * incremental.cc (can_incremental_update): New function. + * incremental.h (can_incremental_update): New function. + * layout.cc (Layout::init_fixed_output_section): Call it. + (Layout::make_output_section): Don't allow patch space in .eh_frame. + * object.cc (Sized_relobj_file::do_layout): Call + can_incremental_update. + +2011-09-13 Cary Coutant + + * configure.ac: Check for glibc support for gnu_indirect_function + support with static linking, setting automake conditional + IFUNC_STATIC. + * Makefile.in: Regenerate. + * configure: Regenerate. + + * testsuite/Makefile.am (ifuncmain1static, ifuncmain2static) + (ifuncmain4static, ifuncmain5static, ifuncmain7static): Add check + for IFUNC_STATIC. + * testsuite/Makefile.in: Regenerate. + +2011-09-13 Cary Coutant + + * incremental.cc (Sized_relobj_incr::do_layout): Call + report_comdat_group for kept comdat sections. + * testsuite/Makefile.am (incremental_comdat_test_1): New test. + * testsuite/Makefile.in: Regenerate. + * testsuite/incr_comdat_test_1.cc: New source file. + * testsuite/incr_comdat_test_2_v1.cc: New source file. + * testsuite/incr_comdat_test_2_v2.cc: New source file. + * testsuite/incr_comdat_test_2_v3.cc: New source file. + +2011-09-13 Ian Lance Taylor + + * object.cc (Sized_relobj_file::do_layout): Remove unused local + variable external_symbols_offset. + +2011-09-12 Ian Lance Taylor + + * object.cc (Sized_relobj_file::do_layout): Remove assertion which + triggered if object has no symbols. + +2011-09-09 David S. Miller + + * output.cc (Output_fill_debug_info::do_write): Use Swap_unaligned. + (Output_fill_debug_line::do_write): Likewise. + +2011-08-29 Cary Coutant + + * output.cc: (Output_fill_debug_info::do_minimum_hole_size): Add + casts to match formatting specs. + (Output_fill_debug_line::do_minimum_hole_size): Likewise. + +2011-08-26 Cary Coutant + + * layout.cc (Free_list::allocate): Provide guarantee of minimum + remaining hole size when allocating. + (Layout::make_output_section): Set fill methods for debug sections. + * layout.h (Free_list::Free_list_node): Move from private to + public. + (Free_list::set_min_hole_size): New function. + (Free_list::begin, Free_list::end): New functions. + (Free_list::min_hole_): New data member. + * output.cc: Include dwarf.h. + (Output_fill_debug_info::do_minimum_hole_size): New function. + (Output_fill_debug_info::do_write): New function. + (Output_fill_debug_line::do_minimum_hole_size): New function. + (Output_fill_debug_line::do_write): New function. + (Output_section::Output_section): Initialize new data member. + (Output_section::set_final_data_size): Ensure patch space is larger + than minimum hole size. + (Output_section::do_write): Fill holes in debug sections. + * output.h (Output_fill): New class. + (Output_fill_debug_info): New class. + (Output_fill_debug_line): New class. + (Output_section::set_free_space_fill): New function. + (Output_section::free_space_fill_): New data member. + * testsuite/Makefile.am (incremental_test_3): Add + --incremental-patch option. + (incremental_test_4): Likewise. + (incremental_test_5): Likewise. + (incremental_test_6): Likewise. + (incremental_copy_test): Likewise. + (incremental_common_test_1): Likewise. + * testsuite/Makefile.in: Regenerate. + +2011-08-26 Nick Clifton + + * po/es.po: Updated Spanish translation. + +2011-08-01 Cary Coutant + + * gold/testsuite/Makefile.am (justsyms_exec): New testcase. + * gold/testsuite/Makefile.in: Regenerate. + * gold/testsuite/justsyms_exec.c: New source file. + * gold/testsuite/justsyms_lib.c: New source file. + +2011-08-01 Cary Coutant + + * layout.cc (Layout::set_segment_offsets): Don't realign text + segment if -Ttext was specified. + * object.cc (Sized_relobj_file::Sized_relobj_file): Store the ELF + file type. + * object.h (Sized_relobj_file::e_type): New function. + (Sized_relobj_file::e_type_): New data member. + * symtab.cc (Symbol_table::add_from_relobj): Don't add section + base address for ET_EXEC files. + * target.cc (Target::do_make_elf_object_implementation): Allow + ET_EXEC files with --just-symbols option. + +2011-07-28 Cary Coutant + + * workqueue-internal.h (Workqueue_threader::should_cancel_thread): + Add thread_number parameter. + (Workqueue_threader_threadpool::should_cancel_thread): Likewise. + * workqueue-threads.cc + (Workqueue_threader_threadpool::should_cancel_thread): Cancel + current thread if its thread number is greater than desired thread + count. + * workqueue.cc (Workqueue_threader_single::should_cancel_thread): + Add thread_number parameter. + (Workqueue::should_cancel_thread): Likewise. + (Workqueue::find_runnable_or_wait): Pass thread_number to + should_cancel_thread. + * workqueue.h (Workqueue::should_cancel_thread): Add thread_number + parameter. + +2011-07-22 Sriraman Tallam + + * symtab.cc (Symbol_table::add_from_relobj): Mark symbol as referenced + only after checking if it cannot be forced local. + * symtab.h (is_externally_visible): Check if the symbol is not forced + local. + +2011-07-15 Ian Lance Taylor + + * options.h (class General_options): Add --print-output-format. + Move -EL next to -EB, for better --help output. + * target-select.cc: Include , "options.h", and + "parameters.h". + (Target_selector::do_target_bfd_name): New function. + (print_output_format): New function. + * target-select.h (class Target_selector): Update declarations. + (Target_selector::target_bfd_name): New function. + (print_output_format): Declare. + * main.cc: Include "target-select.h". + (main): Handle --print-output-format. + * gold.cc: Include "target-select.h". + (queue_initial_tasks): Handle --print-output-format when there are + no input files. + * parameters.cc (parameters_force_valid_target): Give a better + error message if -EB/-EL does not match target. + * freebsd.h (Target_selector_freebsd::do_target_bfd_name): New + function. + +2011-07-15 Ian Lance Taylor + + * i386.cc (class Output_data_plt_i386): Add layout_ field. + (Output_data_plt_i386::Output_data_plt_i386): Initialize layout_. + (Output_data_plt_i386::do_write): Write address of .dynamic + section to first entry in .got.plt section. + * x86_64.cc (class Output_data_plt_x86_64): Add layout_ field. + (Output_data_plt_x86_64::Output_data_plt_x86_64) [both versions]: + Initialize layout_. + (Output_data_plt_x86_64::do_write): Write address of .dynamic + section to first entry in .got.plt section. + * layout.h (Layout::dynamic_section): New function. + +2011-07-13 Sriraman Tallam + + * archive.cc (Archive::get_elf_object_for_member): Add extra parameter + to claim_file call. + * layout.cc (Layout::Layout): Initialize section_ordering_specified_, + input_section_position_, and input_section_glob_. + (read_layout_from_file): Call function section_ordering_specified. + * layout.h (is_section_ordering_specified): New function. + (section_ordering_specified): New function. + (section_ordering_specified_): New boolean member. + * main.cc(main): Call load_plugins after layout object is defined. + * output.cc (Output_section::add_input_section): Use + function section_ordering_specified to check if section ordering is + needed. + * output.cc (Output_section::add_relaxed_input_section): Use + function section_ordering_specified to check if section ordering is + needed. + (Output_section::update_section_layout): New function. + (Output_section::sort_attached_input_sections): Check if input section + must be reordered. + * output.h (Output_section::update_section_layout): New function. + * plugin.cc (get_section_count): New function. + (get_section_type): New function. + (get_section_name): New function. + (get_section_contents): New function. + (update_section_order): New function. + (allow_section_ordering): New function. + (Plugin::load): Add the new interfaces to the transfer vector. + (Plugin_manager::load_plugins): New parameter. + (Plugin_manager::all_symbols_read): New parameter. + (Plugin_manager::claim_file): New parameter. Save the elf object for + unclaimed objects. + (Plugin_manager::get_elf_object): New function. + (Plugin_manager::get_view): Change to directly use the bool to check + if get_view is called from claim_file_hook. + * plugin.h (input_objects): New function + (Plugin__manager::load_plugins): New parameter. + (Plugin_manager::claim_file): New parameter. + (Plugin_manager::get_elf_object): New function. + (Plugin_manager::in_claim_file_handler): New function. + (Plugin_manager::in_claim_file_handler_): New member. + (layout): New function. + * readsyms.cc (Read_symbols::do_read_symbols): Call the claim_file + handler with an extra parameter. Make the elf object before calling + claim_file handler. + * testsuite/plugin_test.c (get_section_count): New function pointer. + (get_section_type): New function pointer. + (get_section_name): New function pointer. + (get_section_contents): New function pointer. + (update_section_order): New function pointer. + (allow_section_ordering): New function pointer. + (onload): Check if the new interfaces exist. + +2011-07-13 Ian Lance Taylor + + * i386.cc (Target_i386::got_section): If -z now, make .got.plt a + relro section. + * x86_64.cc (Target_x86_64::got_section): Likewise. + * testsuite/Makefile.am (check_PROGRAMS): Add relro_now_test. + (relro_now_test_SOURCES): New variable. + (relro_now_test_DEPENDENCIES): New variable. + (relro_now_test_LDFLAGS): New variable. + (relro_now_test_LDADD): New variable. + (relro_now_test.so): New target. + * testsuite/Makefile.in: Rebuild. + +2011-07-12 Ian Lance Taylor + + PR gold/12980 + * i386.cc (Target_i386::Scan::global): For a GOT reloc, use a + GLOB_DAT relocation rather than a RELATIVE relocation for a + protected symbol when creating a shared library. + * x86_64.cc (Target_x86_64::Scan::global): Likewise. + * testsuite/protected_1.cc (f2, get_f2_addr): New functions. + * testsuite/protected_main_1.cc (main): Test that protected + function has same address. + +2011-07-11 Ian Lance Taylor + + PR gold/12979 + * options.h (class General_options): Add -Bgroup. + * options.cc (General_options::finalize): If -Bgroup is set, + default to --unresolved-symbols=report-all. + * layout.cc (Layout::finish_dynamic_section): Implement -Bgroup. + * target-reloc.h (issue_undefined_symbol_error): Handle + --unresolved-symbols=report-all. + +2011-07-08 Ian Lance Taylor + + PR gold/11985 + * layout.cc (Layout::create_initial_dynamic_sections): Don't crash + if linker script discards key sections. + (Layout::create_dynamic_symtab): Likewise. + (Layout::assign_local_dynsym_offsets): Likewise. + (Layout::sized_create_version_sections): Likewise. + (Layout::create_interp): Likewise. + (Layout::finish_dynamic_section): Likewise. + (Layout::set_dynamic_symbol_size): Likewise. + +2011-07-08 Ian Lance Taylor + + PR gold/12386 + * options.h (class General_options): Add --unresolved-symbols. + * target-reloc.h (issue_undefined_symbol_error): Check + --unresolved-symbols. Add comments. + +2011-07-08 Ian Lance Taylor + + * testsuite/odr_violation2.cc (Ordering::operator()): Make + expression more complex. + +2011-07-08 Ian Lance Taylor + + PR gold/11317 + * target-reloc.h (issue_undefined_symbol_error): New inline + function, broken out of relocate_section. + (relocate_section): Call issue_undefined_symbol_error. + * i386.cc (Target_i386::Relocate::relocate_tls): Don't crash if + there is no TLS segment if we are about to issue an undefined + symbol error. + * x86_64.cc (Target_x86_64::relocate_tls): Likewise. + +2011-07-08 Ian Lance Taylor + + PR gold/12279 + * resolve.cc (Symbol_table::should_override): Add fromtype + parameter. Change all callers. Give error when linking together + TLS and non-TLS symbol. + (Symbol_table::should_override_with_special): Add fromtype + parameter. Change all callers. + * i386.cc (Target_i386::Relocate::relocate_tls): Don't crash if + there is no TLS segment if we have reported some errors. + * x86_64.cc (Target_x86_64::relocate_tls): Likewise. + +2011-07-08 Ian Lance Taylor + + PR gold/12372 + * target.h (Target::plt_address_for_global): New function. + (Target::plt_address_for_local): New function. + (Target::plt_section_for_global): Remove. + (Target::plt_section_for_local): Remove. + (Target::do_plt_address_for_global): New virtual function. + (Target::do_plt_address_for_local): New virtual function. + (Target::do_plt_section_for_global): Remove. + (Target::do_plt_section_for_local): Remove. + (Target::register_global_plt_entry): Add Symbol_table and Layout + parameters. + * output.cc (Output_data_got::Got_entry::write): Use + plt_address_for_global and plt_address_for_local. + * layout.cc (Layout::add_target_dynamic_tags): Use size and + address of output section. + * i386.cc (class Output_data_plt_i386): Add irelative_rel_, + got_irelative_, and irelative_count_ fields. Update + declarations. + (Output_data_plt_i386::has_irelative_section): New function. + (Output_data_plt_i386::entry_count): Add irelative_count_. + (Output_data_plt_i386::set_final_data_size): Likewise. + (class Target_i386): Add got_irelative_ and rel_irelative_ + fields. Update declarations. + (Target_i386::Target_i386): Initialize new fields. + (Target_i386::do_plt_address_for_global): New function replacing + do_plt_section_for_global. + (Target_i386::do_plt_address_for_local): New function replacing + do_plt_section_for_local. + (Target_i386::got_section): Create got_irelative_. + (Target_i386::rel_irelative_section): New function. + (Output_data_plt_i386::Output_data_plt_i386): Initialize new + fields. Don't define __rel_iplt_{start,end}. + (Output_data_plt_i386::add_entry): Add symtab and layout + parameters. Change all callers. Use different PLT and GOT for + IFUNC symbols. + (Output_data_plt_i386::add_local_ifunc_entry): Add symtab and + layout parameters. Change all callers. Use different PLT and + GOT. + (Output_data_plt_i386::rel_tls_desc): Fix formatting. + (Output_data_plt_i386::rel_irelative): New function. + (Output_data_plt_i386::address_for_global): New function. + (Output_data_plt_i386::address_for_local): New function. + (Output_data_plt_i386::do_write): Write out IRELATIVE area. Use + IRELATIVE GOT when changing IFUNC GOT entries. + (Target_i386::Scan::global): Use IRELATIVE GOT for IRELATIVE + reloc. + (Target_i386::do_finalize_sections): Create the __rel_iplt symbols + if we didn't create an IRELATIVE GOT. + (Target_i386::Relocate::relocate): Use plt_address_for_global and + plt_address_for_local. + (Target_i386::do_dynsym_value): Use plt_address_for_global. + * x86_64.cc (class Output_data_plt_x86_64): Add irelative_rel_, + got_irelative_, and irelative_count_ fields. Update + declarations. + (Output_data_plt_x86_64::Output_data_plt_x86_64) [both versions]: + Initialize new fields. Remove symtab parameter. Change all + callers. + (Output_data_plt_x86_64::get_tlsdesc_plt_offset): Add + irelative_count_. + (Output_data_plt_x86_64::has_irelative_section): New function. + (Output_data_plt_x86_64::entry_count): Add irelative_count_. + (class Target_x86_64): Add got_irelative_ and rel_irelative_ + fields. Update declarations. + (Target_x86_64::Target_x86_64): Initialize new fields. + (Target_x86_64::do_plt_address_for_global): New function replacing + do_plt_section_for_global. + (Target_x86_64::do_plt_address_for_local): New function replacing + do_plt_section_for_local. + (Target_x86_64::got_section): Create got_irelative_. + (Target_x86_64::rela_irelative_section): New function. + (Output_data_plt_x86_64::init): Remove symtab parameter. Change + all callers. Don't create __rel_iplt_{start,end}. + (Output_data_plt_x86_64::add_entry): Add symtab and layout + parameters. Change all callers. Use different PLT and GOT for + IFUNC symbols. + (Output_data_plt_x86_64::add_local_ifunc_entry): Add symtab and + layout parameters. Change all callers. Use different PLT and + GOT. + (Output_data_plt_x86_64::add_relocation): Add symtab and layout + parameters. Change all callers. Use different PLT and GOT for + IFUNC symbols. + (Output_data_plt_x86_64::rela_tlsdesc): Fix formatting. + (Output_data_plt_x86_64::rela_irelative): New function. + (Output_data_plt_x86_64::address_for_global): New function. + (Output_data_plt_x86_64::address_for_local): New function. + (Output_data_plt_x86_64::set_final_data_size): Likewise. + (Output_data_plt_x86_64::do_write): Write out IRELATIVE area. + (Target_x86_64::init_got_plt_for_update): Create got_irelative_. + (Target_x86_64::register_global_plt_entry): Add symtab and layout + parameters. + (Target_x86_64::Scan::global): Use IRELATIVE GOT for IRELATIVE + reloc. + (Target_x86_64::do_finalize_sections): Create the __rela_iplt + symbols if we didn't create an IRELATIVE GOT. + (Target_x86_64::Relocate::relocate): Use plt_address_for_global and + plt_address_for_local. + (Target_x86_64::do_dynsym_value): Use plt_address_for_global. + * testsuite/ifuncvar1.c: New test file. + * testsuite/ifuncvar2.c: New test file. + * testsuite/ifuncvar3.c: New test file. + * testsuite/Makefile.am (check_PROGRAMS): Add ifuncvar. + (ifuncvar1_pic.o, ifuncvar2_pic.o, ifuncvar.so): New targets. + (ifuncvar_SOURCES, ifuncvar_DEPENDENCIES): New variables. + (ifuncvar_LDFLAGS, ifuncvar_LDADD): New variables. + * testsuite/Makefile.in: Rebuild. + +2011-07-07 Cary Coutant + + * testsuite/Makefile.am (two_file_test_1_v1_ndebug.o): New target. + (two_file_test_1_ndebug.o): Likewise. + (two_file_test_1b_ndebug.o): Likewise. + (two_file_test_2_ndebug.o): Likewise. + (two_file_test_main_ndebug.o): Likewise. + (incremental_test_2): Link with no-debug versions. + +2011-07-06 Cary Coutant + + * gold/incremental.cc + (Output_section_incremental_inputs::write_info_blocks): Check for + hidden and internal symbols. + +2011-07-06 Cary Coutant + + * incremental.cc (Sized_incremental_binary::do_file_has_changed): + Check disposition for startup file. + (Incremental_inputs::report_command_line): Ignore + --incremental-startup-unchanged option. + * options.cc (General_options::parse_incremental_startup_unchanged): + New function. + (General_options::General_options): Initialize new data member. + * options.h (Incremental_disposition): Add INCREMENTAL_STARTUP. + (General_options): Add --incremental-startup-unchanged option. + (General_options::incremental_startup_disposition): New function. + (General_options::incremental_startup_disposition_): New data member. + +2011-07-06 Cary Coutant + + * incremental.cc (Sized_incremental_binary::setup_readers): Pass + input file index to Script_info ctor. + (Sized_incremental_binary::do_file_has_changed): Find the + command-line argument for files named in scripts. + * incremental.h (Script_info::Script_info): New ctor + with input file index. + (Script_info::input_file_index): New function. + (Script_info::input_file_index_): New data member. + (Incremental_binary::get_library): Add const. + (Incremental_binary::get_script_info): Add const. + * readsyms.cc (Read_member::is_runnable): Check for this_blocker_. + * testsuite/Makefile.am (incremental_test_5): New test case. + (incremental_test_6): New test case. + * testsuite/Makefile.in: Regenerate. + +2011-07-06 Cary Coutant + + * incremental.cc (Sized_incremental_binary::do_check_inputs): Add + debug output when command lines differ. + +2011-07-06 Cary Coutant + + * incremental.cc (Incremental_inputs::report_command_line): Ignore + --incremental-patch option. + * layout.cc (Free_list::allocate): Extend allocation beyond original + end if enabled. + (Layout::make_output_section): Mark sections that should get + patch space. + * options.cc (parse_percent): New function. + * options.h (parse_percent): New function. + (DEFINE_percent): New macro. + (General_options): Add --incremental-patch option. + * output.cc (Output_section::Output_section): Initialize new data + members. + (Output_section::add_input_section): Print section name when out + of patch space. + (Output_section::add_output_section_data): Likewise. + (Output_section::set_final_data_size): Add patch space when + doing --incremental-full. + (Output_section::do_reset_address_and_file_offset): Remove patch + space. + (Output_segment::set_section_list_addresses): Print debug output + only if --incremental-update. + * output.h (Output_section::set_is_patch_space_allowed): New function. + (Output_section::is_patch_space_allowed_): New data member. + (Output_section::patch_space_): New data member. + * parameters.cc (Parameters::incremental_full): New function. + * parameters.h (Parameters::incremental_full): New function + * testsuite/Makefile.am (incremental_test_2): Add test for + --incremental-patch option. + * testsuite/Makefile.in: Regenerate. + * testsuite/two_file_test_1_v1.cc (t1, t2, t3): Add comments. + (t18): Remove function body. + +2011-07-05 Doug Kwan + + PR gold/12771 + * arm.cc (Arm_relocate_functions::abs8): Use int32_t for addend and + Arm_Address type for relocation result. + (Arm_relocate_functions::abs16): Use unaligned access. Also fix + overflow check. + (Arm_relocate_functions::abs32): Use unaligned access. + (Arm_relocate_functions::rel32): Ditto. + (Arm_relocate_functions::prel31): Ditto. + (Arm_exidix_cantunwind::do_fixed_endian_write): Ditto. + * testsuite/Makefile.am: Add new test arm_unaligned_reloc for unaligned + static data relocations. + * testsuite/Makefile.in: Regnerate. + * testsuite/arm_unaligned_reloc.{s,sh}: New files. + +2011-07-05 Ian Lance Taylor + + PR gold/12392 + * i386.cc (Target_i386::do_finalize_sections): Define __rel_iplt + symbols if necessary. + * x86_64.cc (Target_x86_64::do_finalize_sections): Likewise. + +2011-07-05 Ian Lance Taylor + + PR gold/12952 + * resolve.cc (Symbol::override_base_with_special): Simply override + version with special symbol version, ignoring previous version. + +2011-07-05 Ian Lance Taylor + + * object.cc (Sized_relobj_file::include_section_group): Add + information to comment about signature location. + +2011-07-02 Ian Lance Taylor + + PR gold/12957 + * options.h (class General_options): Add -f and -F. + * options.cc (General_options::finalize): Fatal error if -f/-F + are used without -shared. + * layout.cc (Layout::finish_dynamic_section): Implement -f/-F. + +2011-07-02 Ian Lance Taylor + + * dirsearch.cc (Dir_cache::read_files): Ignore ENOTDIR errors. + +2011-07-01 Ian Lance Taylor + + PR gold/12525 + PR gold/12952 + * resolve.cc (Symbol::override_base_with_special): Don't override + the version if the overriding symbol has a different name. + * dynobj.cc (Versions::add_def): Add dynpool parameter. Change + all callers. If we give an error about an undefined version, + define the base version if necessary. + * dynobj.h (class Versions): Update declaration. + * testsuite/weak_alias_test_5.cc: New file. + * testsuite/weak_alias_test.script: New file. + * testsuite/weak_alias_test_main.cc: Check that versioned_symbol + and versioned_alias have the right value, and call t2. + * testsuite/Makefile.am (weak_alias_test_DEPENDENCIES): Add + weak_alias_test_5.so. + (weak_alias_test_LDADD): Likewise. + (weak_alias_test_5_pic.o, weak_alias_test_5.so): New targets. + * testsuite/Makefile.in: Rebuild. + +2011-07-01 Ian Lance Taylor + + PR gold/12525 + * options.h (class General_options): Support -z notext. + * testsuite/Makefile.am (two_file_shared_1_nonpic.so): Use + -Wl,-z,notext. + (two_file_shared_nonpic.so): Likewise. + (two_file_shared_mixed.so): Likewise. + (two_file_shared_mixed_1.so): Likewise. + (weak_undef_lib_nonpic.so): Likewise. + (alt/weak_undef_lib_nonpic.so): Likewise. + (tls_test_shared_nonpic.so): Likewise. + * testsuite/Makefile.in: Rebuild. + +2011-07-01 Ian Lance Taylor + + PR gold/12525 + * configure.ac: Test whether static linking works, setting + the automake conditional HAVE_STATIC. + * testsuite/Makefile.am: Disable tests using -static if + HAVE_STATIC is not true. + * configure, testsuite/Makefile.in: Rebuild. + +2011-07-01 Ian Lance Taylor + + PR gold/12525 + * ehframe.cc (Eh_frame_hdr::get_fde_pc): Handle DW_EH_PE_datarel. + Assert if we see DW_EH_PE_indirect. + * target.h (Target::ehframe_datarel_base): New function. + (Target::do_ehframe_datarel_base): New target function. + * i386.cc (Target_i386::do_ehframe_datarel_base): New function. + * x86_64.cc (Target_x86_64::do_ehframe_datarel_base): New + function. + +2011-07-01 Ian Lance Taylor + + PR gold/12571 + * options.h (class General_options): Add + --ld-generated-unwind-info. + * ehframe.cc (Fde::write): Add address parameter. Change all + callers. If associated with PLT, fill in address and size. + (Cie::set_output_offset): Only add merge mapping if there is an + object. + (Cie::write): Add address parameter. Change all callers. + (Eh_frame::add_ehframe_for_plt): New function. + * ehframe.h (class Fde): Update declarations. Move shndx_ and + input_offset_ fields into union u_, with new plt field. + (Fde::Fde): Adjust for new union field. + (Fde::Fde) [Output_data version]: New constructor. + (Fde::add_mapping): Only add merge mapping if there is an object. + (class Cie): Update declarations. + (class Eh_frame): Declare add_ehframe_for_plt. + * layout.cc (Layout::layout_eh_frame): Break out code into + make_eh_frame_section, and call it. + (Layout::make_eh_frame_section): New function. + (Layout::add_eh_frame_for_plt): New function. + * layout.h (class Layout): Update declarations. + * merge.cc (Merge_map::add_mapping): Add assertion. + * i386.cc: Include "dwarf.h". + (class Output_data_plt_i386): Make first_plt_entry, + dyn_first_plt_entry, exec_plt_entry, and dyn_plt_entry const. Add + plt_eh_frame_cie_size, plt_eh_frame_fde_size, plt_eh_frame_cie, + and plt_eh_frame_fde. + (Output_data_plt_i386::Output_data_plt_i386): Align to 16-byte + boundary. Call add_eh_frame_for_plt if appropriate. + * x86_64.cc: Include "dwarf.h". + (class Output_data_plt_x86_64): Align to 16-byte boundary. Make + first_plt_entry, plt_entry and tlsdesc_plt_entry const. Add + plt_eh_frame_cie_size, plt_eh_frame_fde_size, plt_eh_frame_cie, + and plt_eh_frame_fde. + (Output_data_plt_x86_64::init): Call add_eh_frame_for_plt if + appropriate. + +2011-06-29 Ian Lance Taylor + + PR gold/12629 + * object.cc (Sized_relobj_file::layout_section): Change shdr + parameter to be const. + (Sized_relobj_file::layout_eh_frame_section): New function, broken + out of do_layout. + (Sized_relobj_file::do_layout): Defer .eh_frame sections if + appropriate. Call layout_eh_frame_section. + (Sized_relobj_file::do_layout_deferred_sections): Handle .eh_frame + sections. + * object.h (class Sized_relobj_file): Update declarations. + +2011-06-29 Ian Lance Taylor + + PR gold/12652 + * script.cc (Token::integer_value): Accept trailing M/m/K/k + modifier. + (Lex::gather_token): Accept trailing M/m/K/k for integers. + +2011-06-29 Ian Lance Taylor + + PR gold/12675 + * object.cc (Sized_relobj_file::check_eh_frame_flags): Check for + SHT_X86_64_UNWIND. + * layout.cc (Layout::layout_eh_frame): Likewise. + +2011-06-29 Ian Lance Taylor + + PR gold/12695 + * layout.cc (Layout::symtab_section_shndx): New function. + * layout.h (class Layout): Declare symtab_section_shndx. + * output.cc (Output_section::write_header): Call it. + +2011-06-29 Ian Lance Taylor + + PR gold/12818 + * symtab.cc (Symbol::should_add_dynsym_entry): Don't add undefined + symbols which are not used in a relocation. + +2011-06-28 Ian Lance Taylor + + PR gold/12898 + * layout.cc (Layout::segment_precedes): Don't crash if a linker + script create indistinguishable segments. + (Layout::set_segment_offsets): Use stable_sort when sorting + segments. Pass this to Compare_segments constructor. + * layout.h (class Layout): Make segment_precedes non-static. + (class Compare_segments): Change from struct to class. Add + layout_ field. Add constructor. + * script-sections.cc + (Script_sections::attach_sections_using_phdrs_clause): Rename + local orphan to is_orphan. Don't report failure to put empty + section in segment. On attachment failure, report name of + section, and attach to first PT_LOAD segment. + +2011-06-28 Ian Lance Taylor + + PR gold/12934 + * target-select.cc (Target_selector::Target_selector): Add + emulation parameter. Change all callers. + (select_target_by_bfd_name): Rename from select_target_by_name. + Change all callers. + (select_target_by_emulation): New function. + (supported_emulation_names): New function. + * target-select.h (class Target_selector): Add emulation_ field. + Update declarations. + (Target_selector::recognize_by_bfd_name): Rename from + recognize_by_name. Change all callers. + (Target_selector::supported_bfd_names): Rename from + supported_names. Change all callers. + (Target_selector::recognize_by_emulation): New function. + (Target_selector::supported_emulations): New function. + (Target_selector::emulation): New function. + (Target_selector::do_recognize_by_bfd_name): Rename from + do_recognize_by_name. Change all callers. + (Target_selector::do_supported_bfd_names): Rename from + do_supported_names. Change all callers. + (Target_selector::do_recognize_by_emulation): New function. + (Target_selector::do_supported_emulations): New function. + (select_target_by_bfd_name): Change name in declaration. + (select_target_by_emulation): Declare. + (supported_emulation_names): Declare. + * parameters.cc (parameters_force_valid_target): Try to find + target based on emulation from -m option. + * options.h (class General_options): Change doc string for -m. + * options.cc (help): Print emulations. + (General_options::parse_V): Likewise. + * freebsd.h (Target_selector_freebsd::Target_selector_freebsd): + Add emulation parameter. Change all callers. + +2011-06-28 Ian Lance Taylor + + * target.h (class Target): Add osabi_ field. + (Target::osabi): New function. + (Target::set_osabi): New function. + (Target::Target): Initialize osabi_. + (Target::do_adjust_elf_header): Make pure virtual. + (Sized_target::do_adjust_elf_header): Declare. + * target.cc (Sized_target::do_adjust_elf_header): New function. + (class Sized_target): Instantiate all versions. + * freebsd.h (class Target_freebsd): Remove. + (Target_selector_freebsd::do_recognize): Call set_osabi on + Target. + (Target_selector_freebsd::do_recognize_by_name): Likewise. + (Target_selector_freebsd::set_osabi): Remove. + * i386.cc (class Target_i386): Inherit from Sized_target rather + than Target_freebsd. + * x86_64.cc (class Target_x86_64): Likewise. + +2011-06-28 Ian Lance Taylor + + * target.h (Target::can_check_for_function_pointers): Rewrite. + Make non-virtual. + (Target::can_icf_inline_merge_sections): Likewise. + (Target::section_may_have_icf_unsafe_poineters): Likewise. + (Target::Target_info): Add can_icf_inline_merge_sections field. + (Target::do_can_check_for_function_pointers): New virtual + function. + (Target::do_section_may_have_icf_unsafe_pointers): Likewise. + * arm.cc (Target_arm::do_can_check_for_function_pointers): Rename + from can_check_for_function_pointers, move in file. + (Target_arm::do_section_may_have_icf_unsafe_pointers): Rename from + section_may_have_icf_unsafe_poineters, move in file. + (Target_arm::arm_info): Initialize can_icf_inline_merge_sections. + * i386.cc (Target_i386::do_can_check_for_function_pointers): + Rename from can_check_for_function_pointers, move in file. + (Target_i386::can_icf_inline_merge_sections): Remove. + (Target_i386::i386_info): Initialize + can_icf_inline_merge_sections. + * powerpc.cc (Target_powerpc::powerpc_info) [all versions]: + Initialize can_icf_inline_merge_sections. + * sparc.cc (Target_sparc::sparc_info) [both version]: Likewise. + * x86_64.cc (Target_x86_64::do_can_check_for_function_pointers): + Rename from can_check_for_function_pointers, move in file. + (Target_x86_64::can_icf_inline_merge_sections): Remove. + (Target_x86_64::x86_64_info): Initialize + can_icf_inline_merge_sections. + * testsuite/testfile.cc (Target_test::test_target_info): + Likewise. + * icf.cc (get_section_contents): Correct formatting. + +2011-06-27 Ian Lance Taylor + + * symtab.cc (Symbol::versioned_name): New function. + (Symbol_table::add_to_final_symtab): Use versioned_name when + appropriate. + (Symbol_table::sized_write_symbol): Likewise. + * symtab.h (class Symbol): Declare versioned_name. + * stringpool.h (class Stringpool_template): Add variant of add + which takes a std::basic_string. + * testsuite/Makefile.am (check_PROGRAMS): Add ver_test_12. + (ver_test_12_SOURCES, ver_test_12_DEPENDENCIES): New variables. + (ver_test_12_LDFLAGS, ver_test_12_LDADD): New variables. + (ver_test_12.o): New target. + * testsuite/Makefile.in: Rebuild. + +2011-06-27 Doug Kwan + + * arm.cc (Arm_relocate_functions::thm_jump8, + Arm_relocate_functions::thm_jump11): Use a wider signed + type to compute offset. + * testsuite/Makefile.am: Add new tests arm_thm_jump11 and + arm_thm_jump8. + * testsuite/Makefile.in: Regenerate. + * testsuite/arm_branch_in_range.sh: Check test results of + arm_thm_jump11 and arm_thm_jump8. + * testsuite/arm_thm_jump11.s: New test source file. + * testsuite/arm_thm_jump11.t: New linker script. + * testsuite/arm_thm_jump8.s: New test source file. + * testsuite/arm_thm_jump8.t: New linker script. + +2011-06-24 Ian Lance Taylor + + * layout.cc: Include "object.h". + (ctors_sections_in_init_array): New static variable. + (Layout::is_ctors_in_init_array): New function. + (Layout::layout): Add entry to ctors_sections_in_init_array if + appropriate. + * layout.h (class Layout): Declare is_ctors_in_init_array. + * reloc.cc (Sized_relobj_file::do_relocate): Call reverse_words if + is_ctors_reverse_view is set. + (Sized_relobj_file::write_sections): Add layout parameter. Change + all callers. Set is_ctors_reverse_view field of View_size. + (Sized_relobj_file::reverse_words): New function. + * object.h (Sized_relobj_file::View_size): Add + is_ctors_reverse_view field. + (class Sized_relobj_file): Update declarations. + * testsuite/initpri3.c: New test. + * testsuite/Makefile.am: (check_PROGRAMS): Add initpri3a and + initpri3b. + (initpri3a_SOURCES, initpri3a_DEPENDENCIES): New variables. + (initpri3a_LDFLAGS, initpri3a_LDADD): New variables. + (initpri3b_SOURCES, initpri3b_DEPENDENCIES): New variables. + (initpri3b_LDFLAGS, initpri3b_LDADD): New variables. + * testsuite/Makefile.in: Rebuild. + +2011-06-24 Cary Coutant + + * testsuite/Makefile.am: Add in-tree assembler to gcctestdir. + (debug_msg_cdebug.o, odr_violation1_cdebug.o, odr_violation2_cdebug.o) + (debug_msg_cdebug.err): New targets. + * testsuite/Makefile.in: Regenerate. + * testsuite/debug_msg.sh: Check output of link with compressed debug. + Fix checks for link with shared library. + +2011-06-24 Doug Kwan + + * arm.cc (Arm_output_section::append_text_sections_to_list): Do not + skip empty text sections. + * testsuite/arm_exidx_test.s: Test handling of an empty text section. + +2011-06-22 Ian Lance Taylor + + PR gold/12910 + * options.h (class General_options): Add --ctors-in-init-array. + * layout.cc (Layout::get_output_section): Treat SHT_INIT_ARRAY and + friends as SHT_PROGBITS for merging sections. + (Layout::layout): Remove special handling of .init_array and + friends. Don't sort if doing relocatable link. Sort for .ctors + and .dtors if ctors_in_init_array. + (Layout::make_output_section): Force correct section types for + .init_array and friends. Don't sort if doing relocatable link, + Don't sort .ctors and .dtors if ctors_in_init_array. + (Layout::section_name_mapping): Remove .ctors. and .dtorso. + (Layout::output_section_name): Add relobj parameter. Change all + callers. Handle .ctors. and .dtors. in code rather than table. + Handle .ctors and .dtors if ctors_in_init_array. + (Layout::match_file_name): New function, moved from output.cc. + * layout.h (class Layout): Update declarations. + * output.cc: Include "layout.h". + (Input_section_sort_entry::get_priority): New function. + (Input_section_sort_entry::match_file_name): Just call + Layout::match_file_name. + (Output_section::Input_section_sort_init_fini_compare::operator()): + Handle .ctors and .dtors. Sort by explicit priority rather than + by name. + * configure.ac: Remove CONSTRUCTOR_PRIORITY test and conditional. + * testsuite/initpri2.c: New test. + * testsuite/Makefile.am: Don't test CONSTRUCTOR_PRIORITY. + (check_PROGRAMS): Add initpri2. + (initpri2_SOURCES, initpri2_DEPENDENCIES): New variables. + (initpri2_LDFLAGS, initpri2_LDADD): New variables. + * configure, testsuite/Makefile.in: Rebuild. + +2011-06-19 Ian Lance Taylor + + PR gold/12880 + * layout.cc (Layout::attach_allocated_section_to_segment): Add a + .interp section to a PT_INTERP segment even if we have seen a + --dynamic-linker option. Don't do it if we have seen a PHDRS + clause in a linker script. + (Layout::finalize): Don't create a .interp section if we've + already create a PT_INTERP segment. + (Layout::create_interp): Always call choose_output_section (revert + patch of 2011-06-17). Don't create PT_INTERP segment. + * script-sections.cc + (Script_sections::create_note_and_tls_segments): Add a .interp + section to a PT_INTERP segment even if we have seen a + --dynamic-linker option. + +2011-06-18 Ian Lance Taylor + + * layout.cc (Layout::finish_dynamic_section): Don't set DT_TEXTREL + merely because a non-PT_LOAD segment has a dynamic reloc. + +2011-06-18 Ian Lance Taylor + + * layout.cc (Layout::finish_dynamic_section): Don't create + DT_FLAGS entry if not needed. + +2011-06-18 Ian Lance Taylor + + PR gold/12745 + * layout.cc (Layout::layout_eh_frame): Correct handling of + writable .eh_frame section. + +2011-06-17 Ian Lance Taylor + + PR gold/12893 + * resolve.cc (Symbol_table::resolve): Don't give an error if a + symbol is redefined with the exact same object and value. + +2011-06-17 Ian Lance Taylor + + PR gold/12880 + * layout.h (class Layout): Add interp_segment_ field. + * layout.cc (Layout::Layout): Initialize interp_segment_ field. + (Layout::attach_allocated_section_to_segment): If making shared + library, put .interp section in PT_INTERP segment. + (Layout::finalize): Also call create_interp if -dynamic-linker + option was used. + (Layout::create_interp): Assert that there is no PT_INTERP + segment. If not using a SECTIONS clause, use make_output_section. + (Layout::make_output_segment): Set interp_segment_ if PT_INTERP. + * script-sections.cc + (Script_sections::create_note_and_tls_segments): If making shared + library, put .interp section in PT_INTERP segment. + +2011-06-17 Ian Lance Taylor + + * object.cc (Sized_relobj_file::do_layout): Keep warning sections + when making a shared library. + +2011-06-17 Ian Lance Taylor + + * x86_64.cc (Target_x86_64::Scan::check_non_pic): Add gsym + parameter. Change all callers. Don't issue warning about PC32 + against locally defined symbol. + +2011-06-16 Ian Lance Taylor + + * symtab.cc (Warnings::issue_warning): Don't warn if relocation + occurs in same object. + +2011-06-14 Alan Modra + + * po/POTFILES.in: Regenerate. + +2011-06-09 Ian Lance Taylor + + * script-sections.cc + (Orphan_output_section::set_section_addresses): For a relocatable + link set address to 0. + +2011-06-09 Cary Coutant + + PR gold/12804 + * gold/gold.cc (queue_initial_tasks): Warn if --incremental is + used with --compress-debug-sections. + * gold/object.cc (Sized_relobj_file::do_layout): Report + uncompressed size of compressed input sections. + +2011-06-08 Cary Coutant + + PR gold/12804 + * testsuite/two_file_test_2_v1.cc: Change initialization of + v2 to keep it in .data. + +2011-06-07 Cary Coutant + + * common.cc (Symbol_table::do_allocate_commons_list): Call + gold_fallback. + * errors.cc (Errors::fatal): Adjust call to gold_exit. + (Errors::fallback): New function. + (gold_fallback): New function. + * errors.h (Errors::fallback): New function. + * gold.cc (gold_exit): Change status parameter to enum; adjust + all callers. + (queue_initial_tasks): Call gold_fallback. + * gold.h: Include cstdlib. + (Exit_status): New enum type. + (gold_exit): Change status parameter to enum. + (gold_fallback): New function. + * layout.cc (Layout::set_section_offsets): Call gold_fallback. + (Layout::create_symtab_sections): Likewise. + (Layout::create_shdrs): Likewise. + * main.cc (main): Adjust call to gold_exit. + * output.cc (Output_data_got::add_got_entry): Call gold_fallback. + (Output_data_got::add_got_entry_pair): Likewise. + (Output_section::add_input_section): Likewise. + (Output_section::add_output_section_data): Likewise. + (Output_segment::set_section_list_addresses): Likewise. + * x86_64.cc (Output_data_plt_x86_64::add_entry): Likewise. + +2011-06-07 Cary Coutant + + * layout.cc (Layout::set_segment_offsets): Don't adjust layout + for incremental links. + * output.cc (Output_segment::set_section_list_addresses): Remove + FIXME and test for TLS or BSS. + +2011-06-07 Cary Coutant + + * testsuite/Makefile.am: Add incremental_copy_test, + incremental_common_test_1. + * testsuite/Makefile.in: Regenerate. + * testsuite/common_test_1_v1.c: New source file. + * testsuite/common_test_1_v2.c: New source file. + * testsuite/copy_test_v1.cc: New source file. + +2011-06-07 Cary Coutant + + * common.cc (Symbol_table::do_allocate_commons_list): For incremental + update, allocate common from bss section's free list. + * incremental-dump.cc (dump_incremental_inputs): Print flag for + linker-defined symbols. + * incremental.cc (Sized_incremental_binary::do_process_got_plt): + Skip GOT and PLT entries that are no longer referenced. + (Output_section_incremental_inputs::write_info_blocks): Mark + linker-defined symbols. + (Sized_incr_relobj::do_add_symbols): Process linker-defined symbols. + * output.cc (Output_section::allocate): New function. + * output.h (Output_section::allocate): New function. + * resolve.cc (Symbol_table::report_resolve_problem): Add case for + linker-defined symbols. + (Symbol::override_base_with_special): Copy is_predefined_ flag. + * symtab.cc (Symbol::init_fields): Initialize is_predefined_ flag. + (Symbol::init_base_output_data): Likewise. + (Symbol::init_base_output_segment): Likewise. + (Symbol::init_base_constant): Likewise. + (Sized_symbol::init_output_data): Likewise. + (Sized_symbol::init_output_segment): Likewise. + (Sized_symbol::init_constant): Likewise. + (Symbol_table::do_define_in_output_data): Likewise. + (Symbol_table::do_define_in_output_segment): Likewise. + (Symbol_table::do_define_as_constant): Likewise. + * symtab.h (Symbol::is_predefined): New function. + (Symbol::init_base_output_data): Add is_predefined parameter. + (Symbol::init_base_output_segment): Likewise. + (Symbol::init_base_constant): Likewise. + (Symbol::is_predefined_): New data member. + (Sized_symbol::init_output_data): Add is_predefined parameter. + (Sized_symbol::init_output_segment): Likewise. + (Sized_symbol::init_constant): Likewise. + (enum Symbol_table::Defined): Add INCREMENTAL_BASE. + +2011-06-07 Cary Coutant + + * copy-relocs.cc (Copy_relocs::copy_reloc): Call make_copy_reloc + instead of emit_copy_reloc. + (Copy_relocs::emit_copy_reloc): Refactor. + (Copy_relocs::make_copy_reloc): New function. + (Copy_relocs::add_copy_reloc): Remove. + * copy-relocs.h (Copy_relocs::emit_copy_reloc): Move to public + section. + (Copy_relocs::make_copy_reloc): New function. + (Copy_relocs::add_copy_reloc): Remove. + * gold.cc (queue_middle_tasks): Emit old COPY relocations from + unchanged input files. + * incremental-dump.cc (dump_incremental_inputs): Print "COPY" flag. + * incremental.cc (Sized_incremental_binary::do_reserve_layout): + Reserve BSS space for COPY relocations. + (Sized_incremental_binary::do_emit_copy_relocs): New function. + (Output_section_incremental_inputs::write_info_blocks): Record + whether a symbol is copied from a shared object. + (Sized_incr_dynobj::do_add_symbols): Record COPY relocations. + * incremental.h (enum Incremental_shlib_symbol_flags): New type. + (INCREMENTAL_SHLIB_SYM_FLAGS_SHIFT): New constant. + (Incremental_input_entry_reader::get_output_symbol_index): Add + is_copy parameter. + (Incremental_binary::emit_copy_relocs): New function. + (Incremental_binary::do_emit_copy_relocs): New function. + (Sized_incremental_binary::Sized_incremental_binary): Initialize + new data member. + (Sized_incremental_binary::add_copy_reloc): New function. + (Sized_incremental_binary::do_emit_copy_relocs): New function. + (Sized_incremental_binary::Copy_reloc): New struct. + (Sized_incremental_binary::Copy_relocs): New typedef. + (Sized_incremental_binary::copy_relocs_): New data member. + * symtab.cc (Symbol_table::add_from_incrobj): Change return type. + * symtab.h (Symbol_table::add_from_incrobj): Change return type. + * target.h (Sized_target::emit_copy_reloc): New function. + * x86_64.cc (Target_x86_64::emit_copy_reloc): New function. + +2011-06-02 Cary Coutant + + PR gold/12163 + * gold/archive.cc (Archive::Archive): Initialize new data member. + (Archive::include_all_members): Return if archive has already been + included. + * gold/archive.h (Archive::include_all_members_): New data member. + +2011-06-02 Nick Clifton + + * dynobj.h: Fix spelling mistake in comment. + * output.cc: Likewise. + +2011-05-31 Doug Kwan + Asier Llano + + PR gold/12826 + * arm.cc (Target_arm::tag_cpu_arch_combine): Fix handling of + arch value that equals to elfcpp::MAX_TAG_CPU_ARCH. + * testsuite/Makefile.am: (MOSTLYCLEANFILES): Clean up. Remove + redundant arm_exidx_test.so. + * testsuite/Makefile.in: Regenerate. + (check_SCRIPTS): Add pr12826.sh + (check_DATA): Add pr12826.stdout + (pr12826.stdout, pr12826.so, pr12826_1.o, pr12826_2.o): New rules. + * testsuite/pr12826.sh: New file. + * testsuite/pr12826_1.s: Ditto. + * testsuite/pr12826_1.s: Ditto. + +2011-05-30 Ian Lance Taylor + + * reloc.cc (Sized_relobj_file::do_read_relocs): Ignore empty reloc + sections. + +2011-05-29 Ian Lance Taylor + + PR gold/12804 + * testsuite/Makefile.am: Use different file name for two_file_test + temporary file for each incremental test. + * testsuite/Makefile.in: Rebuild. + +2011-05-29 Ian Lance Taylor + + * binary.cc (Binary_to_elf::sized_convert): Don't crash if the + binary input file is empty. + +2011-05-27 Ian Lance Taylor + + * testsuite/Makefile.am (ver_test_2.so): Use -Wl,-R,. + (ver_test_9.so): Likewise. + * testsuite/Makefile.in: Rebuild. + +2011-05-26 Cary Coutant + + * incremental-dump.cc (dump_incremental_inputs): Print COMDAT groups. + * incremental.cc (Incremental_inputs::report_input_section): Fix + comment, indentation. + (Incremental_inputs::report_comdat_group): New function. + (Output_section_incremental_inputs::set_final_data_size): Adjust size + of data for incremental input file entry. + (Output_section_incremental_inputs::write_info_blocks): Write COMDAT + group count, COMDAT group signatures. + (Sized_incr_relobj::do_layout): Record kept COMDAT group info from + an unchanged input file. + * incremental.h (Incremental_object_entry::Incremental_object_entry): + Initialize new data member. + (Incremental_object_entry::add_comdat_group): New function. + (Incremental_object_entry::get_comdat_group_count): New function. + (Incremental_object_entry::get_comdat_signature_key): New function. + (Incremental_object_entry::groups_): New data member. + (Incremental_inputs::report_comdat_group): New function. + (Incremental_input_entry_reader::get_symbol_offset): Adjust size of + data for incremental input file entry. + (Incremental_input_entry_reader::get_comdat_group_count): New function. + (Incremental_input_entry_reader::get_input_section): Adjust size of + data for incremental input file entry. + (Incremental_input_entry_reader::get_global_symbol_reader): Likewise. + (Incremental_input_entry_reader::get_comdat_group_signature): New + function. + * object.cc (Sized_relobj::include_section_group): Report kept + COMDAT groups for incremental links. + +2011-05-24 David Meyer + + * dirsearch.cc (Dirsearch::find): Replace n1 and n2 parameters + with name parameter. Add found_name parameter. + * fileread.cc (Input_file::find_file): Adjust code accordingly. + * dirsearch.h (class Dirsearch): Update declaration. + +2011-05-24 Ian Lance Taylor + + * archive.cc (Library_base::should_include_member): Pull in object + from archive if it defines the entry symbol. + * parameters.cc (Parameters::entry): New function. + * parameters.h (class Parameters): Declare entry. + * output.h (class Output_file_header): Remove entry_ field. + * output.cc (Output_file_header::Output_file_header): Remove entry + parameter. Change all callers. + (Output_file_header::entry): Use parameters->entry. + * gold.cc (queue_middle_tasks): Likewise. + * plugin.cc (Plugin_hook::run): Likewise. + +2011-05-24 Cary Coutant + + * gold.cc (queue_initial_tasks): Pass incremental base filename + to Output_file::open_base_file; don't print error message. + * incremental-dump.cc (main): Adjust call to + Output_file::open_for_modification. + * incremental-dump.cc (main): Likewise. + * incremental.cc (Incremental_inputs::report_command_line): + Ignore --incremental-base option when comparing command lines. + Ignore parameter when given as separate argument. + * options.h (class General_options): Add --incremental-base. + * output.cc (Output_file::Output_file): + (Output_file::open_base_file): Add base_name and writable parameters; + read base file into new file; print error message here. + (Output_file::map_no_anonymous): Add writable parameter; adjust all + callers. + * output.h (Output_file::open_for_modification): Rename to... + (Output_file::open_base_file): ...this; add base_name and + writable parameters; adjust all callers. + (Output_file::map_no_anonymous): Add writable parameter; adjust all + callers. + * testsuite/Makefile.am (incremental_test_4): Test + --incremental-base. + * testsuite/Makefile.in: Regenerate. + +2011-05-24 Cary Coutant + + * testsuite/Makefile.am: Add incremental_test_2, incremental_test_3, + incremental_test_4. + * testsuite/Makefile.in: Regenerate. + * testsuite/two_file_test_1_v1.cc: New test source file. + * testsuite/two_file_test_1b_v1.cc: New test source file. + * testsuite/two_file_test_2_v1.cc: New test source file. + +2011-05-24 Cary Coutant + + * dynobj.h (Dynobj::do_dynobj): New function. + * incremental-dump.cc (dump_incremental_inputs): Print as_needed + flag and soname for shared objects. + * incremental.cc (Incremental_inputs::report_object): Make + either Incremental_object_entry or Incremental_dynobj_entry; add + soname to string table. + (Incremental_inputs::report_input_section): Add assertion. + (Output_section_incremental_inputs::set_final_data_size): Adjust + type of input file entry for shared libraries; adjust size of + shared library info entry. + (Output_section_incremental_inputs::write_input_files): Write + as_needed flag for shared libraries. + (Output_section_incremental_inputs::write_info_blocks): Adjust type + of input file entry for shared libraries; write soname. + (Sized_incr_dynobj::Sized_incr_dynobj): Read as_needed flag and + soname from incremental info. + * incremental.h (enum Incremental_input_flags): Add + INCREMENTAL_INPUT_AS_NEEDED. + (Incremental_input_entry::Incremental_input_entry): Initialize new + data member. + (Incremental_input_entry::set_as_needed): New function. + (Incremental_input_entry::as_needed): New function. + (Incremental_input_entry::do_dynobj_entry): New function. + (Incremental_input_entry::as_needed_): New data member. + (Incremental_object_entry::Incremental_object_entry): Don't check + for shared library. + (Incremental_object_entry::do_type): Likewise. + (class Incremental_dynobj_entry): New class. + (Incremental_input_entry_reader::as_needed): New function. + (Incremental_input_entry_reader::get_soname): New function. + (Incremental_input_entry_reader::get_global_symbol_count): Rewrite. + (Incremental_input_entry_reader::get_output_symbol_index): Adjust + size of shared library info entry. + * layout.cc (Layout::finish_dynamic_section): Don't test for + incremental link when adding DT_NEEDED entries. + * object.h (Object::Object): Initialize new data member. + (Object::dynobj): New function. + (Object::set_as_needed): New function. + (Object::as_needed): New function. + (Object::do_dynobj): New function. + (Object::as_needed_): New data member. + +2011-05-24 Cary Coutant + + * incremental-dump.cc (dump_incremental_inputs): Print dynamic reloc + info; adjust display of GOT entries. + * incremental.cc (Sized_incremental_binary::setup_readers): Allocate + vector of input objects; remove file_status_. + (Sized_incremental_binary::do_reserve_layout): Remove file_status_. + (Sized_incremental_binary::do_process_got_plt): Adjust calls to + got_plt reader; call target hooks to reserve GOT entries. + (Output_section_incremental_inputs::set_final_data_size): Adjust size + of input file info header and GOT info entry. + (Output_section_incremental_inputs::write_info_blocks): Write dynamic + relocation info. + (Got_plt_view_info::got_descriptor): Remove. + (Got_plt_view_info::sym_index): New data member. + (Got_plt_view_info::input_index): New data member. + (Local_got_offset_visitor::visit): Write input file index. + (Global_got_offset_visitor::visit): Write 0 for input file index. + (Global_symbol_visitor_got_plt::operator()): Replace got_descriptor + with sym_index and input_index. + (Output_section_incremental_inputs::write_got_plt): Adjust size of + incremental info GOT entry; replace got_descriptor with input_index. + (Sized_relobj_incr::Sized_relobj_incr): Adjust initializers; record + map from input file index to object. + (Sized_relobj_incr::do_layout): Replace direct data member reference + with accessor function. + (Sized_relobj_incr::do_for_all_local_got_entries): Move to base class. + * incremental.h (Incremental_input_entry_reader::get_symbol_offset): + Adjust size of input file info header. + (Incremental_input_entry_reader::get_first_dyn_reloc): New function. + (Incremental_input_entry_reader::get_dyn_reloc_count): New function. + (Incremental_input_entry_reader::get_input_section): Adjust size of + input file info header. + (Incremental_got_plt_reader::Incremental_got_plt_reader): Adjust size + of incremental info GOT entry. + (Incremental_got_plt_reader::get_got_desc): Remove. + (Incremental_got_plt_reader::get_got_symndx): New function. + (Incremental_got_plt_reader::get_got_input_index): New function. + (Sized_incremental_binary::Sized_incremental_binary): Remove + file_status_; add input_objects_. + (Sized_incremental_binary::~Sized_incremental_binary): Remove. + (Sized_incremental_binary::set_file_is_unchanged): Remove. + (Sized_incremental_binary::file_is_unchanged): Remove. + (Sized_incremental_binary::set_input_object): New function. + (Sized_incremental_binary::input_object): New function. + (Sized_incremental_binary::file_status_): Remove. + (Sized_incremental_binary::input_objects_): New data member. + (Sized_relobj_incr): Rename Sized_incr_relobj to this; adjust all + references. + (Sized_relobj_incr::invalid_address): Move to base class. + (Sized_relobj_incr::is_output_section_offset_invalid): Move to base + class. + (Sized_relobj_incr::do_output_section_offset): Likewise. + (Sized_relobj_incr::do_for_all_local_got_entries): Likewise. + (Sized_relobj_incr::section_offsets_): Likewise. + * object.cc (Sized_relobj::do_for_all_local_got_entries): New + function. + (Sized_relobj_file::Sized_relobj_file): Remove local_got_offsets_. + (Sized_relobj_file::layout_section): Replace refs to section_offsets_ + with accessor function. + (Sized_relobj_file::do_layout): Likewise. + (Sized_relobj_file::do_layout_deferred_sections): Likewise. + (Sized_relobj_file::do_for_all_local_got_entries): Move to base class. + (Sized_relobj_file::compute_final_local_value): Replace refs to + section_offsets_ with accessor function. + (Sized_relobj_file::do_finalize_local_symbols): Likewise. + * object.h (Relobj::Relobj): Initialize new data members. + (Relobj::add_dyn_reloc): New function. + (Relobj::first_dyn_reloc): New function. + (Relobj::dyn_reloc_count): New function. + (Relobj::first_dyn_reloc_): New data member. + (Relobj::dyn_reloc_count_): New data member. + (Sized_relobj): Rename Sized_relobj_base to this; adjust all + references. + (Sized_relobj::Address): New typedef. + (Sized_relobj::invalid_address): Move here from child class. + (Sized_relobj::Sized_relobj): Initialize new data members. + (Sized_relobj::sized_relobj): New function. + (Sized_relobj::is_output_section_offset_invalid): Move here from + child class. + (Sized_relobj::get_output_section_offset): Likewise. + (Sized_relobj::local_has_got_offset): Likewise. + (Sized_relobj::local_got_offset): Likewise. + (Sized_relobj::set_local_got_offset): Likewise. + (Sized_relobj::do_for_all_local_got_entries): Likewise. + (Sized_relobj::clear_got_offsets): New function. + (Sized_relobj::section_offsets): Move here from child class. + (Sized_relobj::do_output_section_offset): Likewise. + (Sized_relobj::do_set_section_offset): Likewise. + (Sized_relobj::Local_got_offsets): Likewise. + (Sized_relobj::local_got_offsets_): Likewise. + (Sized_relobj::section_offsets_): Likewise. + (Sized_relobj_file): Rename Sized_relobj to this; adjust all + references. + (Sized_relobj_file::is_output_section_offset_invalid): Move to base + class. + (Sized_relobj_file::sized_relobj): New function + (Sized_relobj_file::local_has_got_offset): Move to base class. + (Sized_relobj_file::local_got_offset): Likewise. + (Sized_relobj_file::set_local_got_offset): Likewise. + (Sized_relobj_file::get_output_section_offset): Likewise. + (Sized_relobj_file::do_for_all_local_got_entries): Likewise. + (Sized_relobj_file::do_output_section_offset): Likewise. + (Sized_relobj_file::do_set_section_offset): Likewise. + (Sized_relobj_file::Local_got_offsets): Likewise. + (Sized_relobj_file::local_got_offsets_): Likewise. + (Sized_relobj_file::section_offsets_): Likewise. + * output.cc (Output_reloc::Output_reloc): Adjust type of relobj + (all constructors). + (set_needs_dynsym_index): Convert relobj to derived class pointer. + (Output_reloc::get_symbol_index): Likewise. + (Output_reloc::local_section_offset): Likewise. + (Output_reloc::get_address): Likewise. + (Output_reloc::symbol_value): Likewise. + (Output_data_got::reserve_slot): Move to class definition. + (Output_data_got::reserve_local): New function. + (Output_data_got::reserve_slot_for_global): Remove. + (Output_data_got::reserve_global): New function. + * output.h (Output_reloc::Output_reloc): Adjust type of relobj + (all constructors, two instantiations). + (Output_reloc::get_relobj): New function (two instantiations). + (Output_reloc::u1_.relobj, Output_reloc::u2_.relobj): Adjust type. + (Output_data_reloc_base::add): Convert relobj to derived class pointer. + (Output_data_reloc::add_global): Adjust type of relobj. + (Output_data_reloc::add_global_relative): Likewise. + (Output_data_reloc::add_symbolless_global_addend): Likewise. + (Output_data_reloc::add_local): Likewise. + (Output_data_reloc::add_local_relative): Likewise. + (Output_data_reloc::add_symbolless_local_addend): Likewise. + (Output_data_reloc::add_local_section): Likewise. + (Output_data_reloc::add_output_section): Likewise. + (Output_data_reloc::add_absolute): Likewise. + (Output_data_reloc::add_target_specific): Likewise. + (Output_data_got::reserve_slot): Move definition here. + (Output_data_got::reserve_local): New function. + (Output_data_got::reserve_global): New function. + * reloc.cc (Sized_relobj_file::do_read_relocs): Replace refs to + section_offsets_ with accessor function. + (Sized_relobj_file::write_sections): Likewise. + (Sized_relobj_file::do_relocate_sections): Likewise. + * target.h (Sized_target::reserve_local_got_entry): New function. + (Sized_target::reserve_global_got_entry): New function. + * x86_64.cc (Target_x86_64::reserve_local_got_entry): New function. + (Target_x86_64::reserve_global_got_entry): New function. + (Target_x86_64::init_got_plt_for_update): Create rela_dyn section. + +2011-05-23 Cary Coutant + + * gold.cc (queue_middle_tasks): Process existing GOT/PLT entries. + * incremental-dump.cc (dump_incremental_inputs): Mask high-order + bit when checking got_type. + * incremental.cc (Sized_incremental_binary::setup_readers): + Store symbol table and string table locations; initialize bit vector + of file status flags. + (Sized_incremental_binary::do_reserve_layout): Set bit flag for + unchanged files. + (Sized_incremental_binary::do_process_got_plt): New function. + (Sized_incremental_binary::get_symtab_view): Use stored locations. + (Output_section_incremental_inputs::set_final_data_size): Record + file index for each input file. + (Output_section_incremental_inputs::write_got_plt): Store file index + instead of input entry offset for each GOT entry. + * incremental.h + (Incremental_input_entry::Incremental_input_entry): Initialize new + data member. + (Incremental_input_entry::set_offset): Store file index. + (Incremental_input_entry::get_file_index): New function. + (Incremental_input_entry::file_index_): New data member. + (Incremental_binary::process_got_plt): New function. + (Incremental_binary::do_process_got_plt): New function. + (Sized_incremental_binary::Sized_incremental_binary): Initialize new + data members. + (Sized_incremental_binary::~Sized_incremental_binary): New destructor. + (Sized_incremental_binary::set_file_is_unchanged): New function. + (Sized_incremental_binary::file_is_unchanged): New function. + (Sized_incremental_binary::do_process_got_plt): New function. + (Sized_incremental_binary::file_status_): New data member. + (Sized_incremental_binary::main_symtab_loc_): New data member. + (Sized_incremental_binary::main_strtab_loc_): New data member. + * output.cc (Output_data_got::Got_entry::write): Add case + RESERVED_CODE. + (Output_data_got::add_global): Call add_got_entry. + (Output_data_got::add_global_plt): Likewise. + (Output_data_got::add_global_with_rel): Likewise. + (Output_data_got::add_global_with_rela): Likewise. + (Output_data_got::add_global_pair_with_rel): Call add_got_entry_pair. + (Output_data_got::add_global_pair_with_rela): Likewise. + (Output_data_got::add_local): Call add_got_entry. + (Output_data_got::add_local_plt): Likewise. + (Output_data_got::add_local_with_rel): Likewise. + (Output_data_got::add_local_with_rela): Likewise. + (Output_data_got::add_local_pair_with_rel): Call add_got_entry_pair. + (Output_data_got::add_local_pair_with_rela): Likewise. + (Output_data_got::reserve_slot): New function. + (Output_data_got::reserve_slot_for_global): New function. + (Output_data_got::add_got_entry): New function. + (Output_data_got::add_got_entry_pair): New function. + (Output_section::add_output_section_data): Edit FIXME. + * output.h + (Output_section_data_build::Output_section_data_build): New + constructor with size parameter. + (Output_data_space::Output_data_space): Likewise. + (Output_data_got::Output_data_got): Initialize new data member; new + constructor with size parameter. + (Output_data_got::add_constant): Call add_got_entry. + (Output_data_got::reserve_slot): New function. + (Output_data_got::reserve_slot_for_global): New function. + (class Output_data_got::Got_entry): Add RESERVED_CODE. + (Output_data_got::add_got_entry): New function. + (Output_data_got::add_got_entry_pair): New function. + (Output_data_got::free_list_): New data member. + * target.h (Sized_target::init_got_plt_for_update): New function. + (Sized_target::register_global_plt_entry): New function. + * x86_64.cc (Output_data_plt_x86_64::Output_data_plt_x86_64): + Initialize new data member; call init; add constructor with PLT count. + (Output_data_plt_x86_64::init): New function. + (Output_data_plt_x86_64::add_relocation): New function. + (Output_data_plt_x86_64::reserve_slot): New function. + (Output_data_plt_x86_64::free_list_): New data member. + (Target_x86_64::init_got_plt_for_update): New function. + (Target_x86_64::register_global_plt_entry): New function. + (Output_data_plt_x86_64::add_entry): Allocate from free list for + incremental updates. + (Output_data_plt_x86_64::add_relocation): New function. + * testsuite/object_unittest.cc (Object_test): Set default options. + +2011-05-16 Ian Lance Taylor + + * options.h (class General_options): Make -i a synonym for -r. + +2011-05-16 Ian Lance Taylor + + * testsuite/tls_test_main.cc: Use semaphores instead of mutexes. + +2011-05-10 Cary Coutant + + * object.cc (Sized_relobj::do_count_local_symbols): Check for + strip_all (-s). + +2011-05-06 Ian Lance Taylor + + * layout.cc (Layout::layout): If the output section flags change, + update the ordering. + +2011-04-25 Cary Coutant + + * incremental-dump.cc (dump_incremental_inputs): Print local + symbol info for each input file. + * incremental.cc + (Output_section_incremental_inputs::set_final_data_size): Add local + symbol info to input file entries in incremental info. + (Output_section_incremental_inputs::write_info_blocks): Likewise. + (Sized_incr_relobj::Sized_incr_relobj): Initialize new data members. + (Sized_incr_relobj::do_add_symbols): Cosmetic change. + (Sized_incr_relobj::do_count_local_symbols): Replace stub with + implementation. + (Sized_incr_relobj::do_finalize_local_symbols): Likewise. + (Sized_incr_relobj::do_relocate): Write the local symbols. + (Sized_incr_dynobj::do_add_symbols): Cosmetic change. + * incremental.h (Incremental_inputs_reader::get_symbol_offset): + Adjust size of input file header. + (Incremental_inputs_reader::get_local_symbol_offset): New function. + (Incremental_inputs_reader::get_local_symbol_count): New function. + (Incremental_inputs_reader::get_input_section): Adjust size of input + file header. + (Incremental_inputs_reader::get_global_symbol_reader): Likewise. + (Sized_incr_relobj::This): New typedef. + (Sized_incr_relobj::sym_size): New const data member. + (Sized_incr_relobj::Local_symbol): New struct. + (Sized_incr_relobj::do_output_local_symbol_count): New function. + (Sized_incr_relobj::do_local_symbol_offset): New function. + (Sized_incr_relobj::local_symbol_count_): New data member. + (Sized_incr_relobj::output_local_dynsym_count_): New data member. + (Sized_incr_relobj::local_symbol_index_): New data member. + (Sized_incr_relobj::local_symbol_offset_): New data member. + (Sized_incr_relobj::local_dynsym_offset_): New data member. + (Sized_incr_relobj::local_symbols_): New data member. + * object.h (Relobj::output_local_symbol_count): New function. + (Relobj::local_symbol_offset): New function. + (Relobj::do_output_local_symbol_count): New function. + (Relobj::do_local_symbol_offset): New function. + (Sized_relobj::do_output_local_symbol_count): New function. + (Sized_relobj::do_local_symbol_offset): New function. + +2011-04-22 Vladimir Simonov + + * descriptors.cc (set_close_on_exec): New function. + (Descriptors::open): Use set_close_on_exec. + * output.cc (S_ISLNK): Define if not defined. + +2011-04-22 Cary Coutant + + * incremental.cc (Sized_incremental_binary::setup_readers): Allocate + global symbol map. + (Sized_incremental_binary::do_apply_incremental_relocs): New function. + (Sized_incr_relobj::do_add_symbols): Add symbols to global symbol map. + (Sized_incr_relobj::do_relocate): Remap section indices in incremental + relocations. + (Sized_incr_dynobj::do_add_symbols): Add symbols to global symbol map. + (Sized_incr_dynobj::do_for_all_global_symbols): Remove FIXME. + (Sized_incr_dynobj::do_for_all_local_got_entries): Likewise. + * incremental.h + (Incremental_inputs_reader::global_symbol_reader_at_offset): New + function. + (Incremental_binary::apply_incremental_relocs): New function. + (Incremental_binary::do_apply_incremental_relocs): New function. + (Sized_incremental_binary::Sized_incremental_binary): Initialize new + data member. + (Sized_incremental_binary::add_global_symbol): New function. + (Sized_incremental_binary::global_symbol): New function. + (Sized_incremental_binary::do_apply_incremental_relocs): New function. + (Sized_incremental_binary::symbol_map_): New data member. + * layout.cc (Layout_task_runner::run): Apply incremental relocations. + * target.h (Sized_target::apply_relocation): New function. + * target-reloc.h (apply_relocation): New function. + * x86_64.cc (Target_x86_64::apply_relocation): New function. + +2011-04-22 Doug Kwan + + * 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.in: Regenerate. + * testsuite/arm_exidx_test.s: New file. + * testsuite/arm_exidx_test.sh: Same. + +2011-04-20 Cary Coutant + + PR gold/12689 + * archive.h (Incremental_archive_entry::Archive_member): + Initialize arg_serial_ (second constructor). + +2011-04-17 Ian Lance Taylor + + * object.cc (Relocate_info::location): Simplify location string. + * errors.cc (Errors::error_at_location): Don't print program + name. + (Errors::warning_at_location): Likewise. + (Errors::undefined_symbol): Likewise. + * testsuite/debug_msg.sh: Update accordingly. + +2011-04-14 Cary Coutant + + * gold/layout.cc (Layout::symtab_section_offset): New function. + * gold/layout.h (Layout::symtab_section_offset): New function. + * gold/reloc.cc (Sized_relobj::do_relocate): Call it. + +2011-04-12 Ian Lance Taylor + + * configure.ac: Check for sys/mman.h and mmap. Check for mremap + with MREMAP_MAYMOVE. + * output.h (class Output_file): Add map_is_allocated_ field. + * output.cc: Only #include if it exists. If mmap is + not available, provide stubs. If mremap is not available, #define + it to gold_mremap. + (MREMAP_MAYMOVE): Define if not defined. + (Output_file::Output_file): Initialize map_is_allocated_. + (Output_file::resize): Check map_is_allocated_. + (Output_file::map_anonymous): If mmap fails, use malloc. + (Output_file::unmap): Don't do anything for an anonymous map. + * fileread.cc: Only #include if it exists. If mmap + is not available, provide stubs. + (File_read::View::~View): Use free rather than delete[]. + (File_read::make_view): Use malloc rather than new[]. If mmap + fails, use malloc. + (File_read::find_or_make_view): Use malloc rather than new[]. + * gold.h: Remove HAVE_REMAP code. + * mremap.c: #include . Only #include if it + exists. Rename mremap to gold_mremap. If mmap is not available + don't do anything. + * configure, config.in: Rebuild. + +2011-04-11 Ian Lance Taylor + + * incremental.cc (Sized_incr_relobj::do_add_symbols): Always + initialize local variable v. + +2011-04-11 Cary Coutant + + * archive.cc (Archive::include_member): Adjust call to + report_object. + (Add_archive_symbols::run): Track argument serial numbers. + (Lib_group::include_member): Likewise. + (Add_lib_group_symbols::run): Adjust call to report_archive_begin. + * archive.h (Incremental_archive_entry::Archive_member): + Initialize arg_serial_. + (Archive_member::arg_serial_): New data member. + * dynobj.cc (Dynobj::Dynobj): Allow input_file_ to be NULL. + (Sized_dynobj::do_add_symbols): Track symbols when doing an + incremental link. + (Sized_dynobj::do_for_all_local_got_entries): New function. + * dynobj.h: (Sized_dynobj::do_for_all_local_got_entries): New + function. + * fileread.cc (get_mtime): New function. + * fileread.h (get_mtime): New function. + * gold.cc (queue_initial_tasks): Check for incremental update. + (process_incremental_input): New function. + (queue_middle_tasks): Don't force valid target for incremental + update. + * incremental-dump.cc (find_input_containing_global): Adjust + size of symbol info entry. + (dump_incremental_inputs): Dump argument serial number and + in_system_directory flag; bias shndx by 1; print symbol names + when dumping per-file symbol lists; use new symbol info readers. + * incremental.cc + (Output_section_incremental_inputs:update_data_size): New function. + (Sized_incremental_binary::setup_readers): Setup input readers + for each input file; build maps for files added from libraries + and scripts. + (Sized_incremental_binary::check_input_args): New function. + (Sized_incremental_binary::do_check_inputs): Build map of argument + serial numbers to input arguments. + (Sized_incremental_binary::do_file_has_changed): Rename + do_file_is_unchanged to this; compare file modification times. + (Sized_incremental_binary::do_init_layout): New function. + (Sized_incremental_binary::do_reserve_layout): New function. + (Sized_incremental_binary::do_get_input_reader): Remove. + (Sized_incremental_binary::get_symtab_view): New function. + (Incremental_checker::can_incrementally_link_output_file): Remove. + (Incremental_inputs::report_command_line): Exclude --debug options. + (Incremental_inputs::report_archive_begin): Add parameter; track + argument serial numbers; don't put input file entry for archive + before archive members. + (Incremental_inputs::report_archive_end): Put input file entry + for archive after archive members. + (Incremental_inputs::report_object): Add parameter; track argument + serial numbers and in_system_directory flag. + (Incremental_inputs::report_script): Add parameter; track argument + serial numbers. + (Output_section_incremental_inputs::set_final_data_size): Adjust + size of symbol info entry; check for forwarding symbols. + (Output_section_incremental_inputs::write_input_files): Write + in_system_directory flag and argument serial number. + (Output_section_incremental_inputs::write_info_blocks): Map section + indices between incremental info and original input file; store + input section index for each symbol. + (class Local_got_offset_visitor): Derive from Got_offset_list::Visitor; + change operator() to visit(). + (class Global_got_offset_visitor): Likewise. + (class Global_symbol_visitor_got_plt): + (Output_section_incremental_inputs::write_got_plt): Use new visitor + classes. + (Sized_incr_relobj::Sized_incr_relobj): New constructor. + (Sized_incr_relobj::do_read_symbols): New function. + (Sized_incr_relobj::do_layout): New function. + (Sized_incr_relobj::do_layout_deferred_sections): New function. + (Sized_incr_relobj::do_add_symbols): New function. + (Sized_incr_relobj::do_should_include_member): New function. + (Sized_incr_relobj::do_for_all_global_symbols): New function. + (Sized_incr_relobj::do_for_all_local_got_entries): New function. + (Sized_incr_relobj::do_section_size): New function. + (Sized_incr_relobj::do_section_name): New function. + (Sized_incr_relobj::do_section_contents): New function. + (Sized_incr_relobj::do_section_flags): New function. + (Sized_incr_relobj::do_section_entsize): New function. + (Sized_incr_relobj::do_section_address): New function. + (Sized_incr_relobj::do_section_type): New function. + (Sized_incr_relobj::do_section_link): New function. + (Sized_incr_relobj::do_section_info): New function. + (Sized_incr_relobj::do_section_addralign): New function. + (Sized_incr_relobj::do_initialize_xindex): New function. + (Sized_incr_relobj::do_get_global_symbol_counts): New function. + (Sized_incr_relobj::do_read_relocs): New function. + (Sized_incr_relobj::do_gc_process_relocs): New function. + (Sized_incr_relobj::do_scan_relocs): New function. + (Sized_incr_relobj::do_count_local_symbols): New function. + (Sized_incr_relobj::do_finalize_local_symbols): New function. + (Sized_incr_relobj::do_set_local_dynsym_indexes): New function. + (Sized_incr_relobj::do_set_local_dynsym_offset): New function. + (Sized_incr_relobj::do_relocate): New function. + (Sized_incr_relobj::do_set_section_offset): New function. + (Sized_incr_dynobj::Sized_incr_dynobj): New function. + (Sized_incr_dynobj::do_read_symbols): New function. + (Sized_incr_dynobj::do_layout): New function. + (Sized_incr_dynobj::do_add_symbols): New function. + (Sized_incr_dynobj::do_should_include_member): New function. + (Sized_incr_dynobj::do_for_all_global_symbols): New function. + (Sized_incr_dynobj::do_for_all_local_got_entries): New function. + (Sized_incr_dynobj::do_section_size): New function. + (Sized_incr_dynobj::do_section_name): New function. + (Sized_incr_dynobj::do_section_contents): New function. + (Sized_incr_dynobj::do_section_flags): New function. + (Sized_incr_dynobj::do_section_entsize): New function. + (Sized_incr_dynobj::do_section_address): New function. + (Sized_incr_dynobj::do_section_type): New function. + (Sized_incr_dynobj::do_section_link): New function. + (Sized_incr_dynobj::do_section_info): New function. + (Sized_incr_dynobj::do_section_addralign): New function. + (Sized_incr_dynobj::do_initialize_xindex): New function. + (Sized_incr_dynobj::do_get_global_symbol_counts): New function. + (make_sized_incremental_object): New function. + (Incremental_library::copy_unused_symbols): New function. + (Incremental_library::do_for_all_unused_symbols): New function. + * incremental.h (enum Incremental_input_flags): New type. + (class Incremental_checker): Remove. + (Incremental_input_entry::Incremental_input_entry): Add argument + serial number. + (Incremental_input_entry::arg_serial): New function. + (Incremental_input_entry::set_is_in_system_directory): New function. + (Incremental_input_entry::is_in_system_directory): New function. + (Incremental_input_entry::arg_serial_): New data member. + (Incremental_input_entry::is_in_system_directory_): New data member. + (class Script_info): Move here from script.h. + (Script_info::Script_info): Add filename parameter. + (Script_info::filename): New function. + (Script_info::filename_): New data member. + (Incremental_script_entry::Incremental_script_entry): Add argument + serial number. + (Incremental_object_entry::Incremental_object_entry): Likewise. + (Incremental_object_entry::add_input_section): Build list of input + sections with map to original shndx. + (Incremental_object_entry::get_input_section_index): New function. + (Incremental_object_entry::shndx_): New data member. + (Incremental_object_entry::name_key_): Rename; adjust all refs. + (Incremental_object_entry::sh_size_): Rename; adjust all refs. + (Incremental_archive_entry::Incremental_archive_entry): Add argument + serial number. + (Incremental_inputs::report_archive_begin): Likewise. + (Incremental_inputs::report_object): Likewise. + (Incremental_inputs::report_script): Likewise. + (class Incremental_global_symbol_reader): New class. + (Incremental_input_entry_reader::Incremental_input_entry_reader): Read + and store flags and input file type. + (Incremental_input_entry_reader::arg_serial): New function. + (Incremental_input_entry_reader::type): Extract type from flags. + (Incremental_input_entry_reader::is_in_system_directory): New function. + (Incremental_input_entry_reader::get_input_section_count): Call + accessor function for type. + (Incremental_input_entry_reader::get_symbol_offset): Call accessor + function for type; adjust size of global symbol entry. + (Incremental_input_entry_reader::get_global_symbol_count): Call + accessor function for type. + (Incremental_input_entry_reader::get_object_count): Likewise. + (Incremental_input_entry_reader::get_object_offset): Likewise. + (Incremental_input_entry_reader::get_member_count): Likewise. + (Incremental_input_entry_reader::get_unused_symbol_count): Likewise. + (Incremental_input_entry_reader::get_member_offset): Likewise. + (Incremental_input_entry_reader::get_unused_symbol): Likewise. + (Incremental_input_entry_reader::Global_symbol_info): Remove. + (Incremental_input_entry_reader::get_global_symbol_info): Remove. + (Incremental_input_entry_reader::get_global_symbol_reader): New + function. + (Incremental_input_entry_reader::get_output_symbol_index): New + function. + (Incremental_input_entry_reader::type_): Remove. + (Incremental_input_entry_reader::flags_): New data member. + (Incremental_inputs_reader::input_file_offset): New function. + (Incremental_inputs_reader::input_file_index): New function. + (Incremental_inputs_reader::input_file): Call input_file_offset. + (Incremental_inputs_reader::input_file_at_offset): New function. + (Incremental_relocs_reader::get_r_type): Reformat. + (Incremental_relocs_reader::get_r_shndx): Reformat. + (Incremental_relocs_reader::get_r_offset): Reformat. + (Incremental_relocs_reader::data): New function. + (Incremental_binary::Incremental_binary): Initialize new data members. + (Incremental_binary::check_inputs): Add cmdline parameter. + (Incremental_binary::file_is_unchanged): Remove. + (Input_reader::arg_serial): New function. + (Input_reader::get_unused_symbol_count): New function. + (Input_reader::get_unused_symbol): New function. + (Input_reader::do_arg_serial): New function. + (Input_reader::do_get_unused_symbol_count): New function. + (Input_reader::do_get_unused_symbol): New function. + (Incremental_binary::input_file_count): New function. + (Incremental_binary::get_input_reader): Change signature to use + index instead of filename. + (Incremental_binary::file_has_changed): New function. + (Incremental_binary::get_input_argument): New function. + (Incremental_binary::get_library): New function. + (Incremental_binary::get_script_info): New function. + (Incremental_binary::init_layout): New function. + (Incremental_binary::reserve_layout): New function. + (Incremental_binary::output_file): New function. + (Incremental_binary::do_check_inputs): New function. + (Incremental_binary::do_file_is_unchanged): Remove. + (Incremental_binary::do_file_has_changed): New function. + (Incremental_binary::do_init_layout): New function. + (Incremental_binary::do_reserve_layout): New function. + (Incremental_binary::do_input_file_count): New function. + (Incremental_binary::do_get_input_reader): Change signature. + (Incremental_binary::input_args_map_): New data member. + (Incremental_binary::library_map_): New data member. + (Incremental_binary::script_map_): New data member. + (Sized_incremental_binary::Sized_incremental_binary): Initialize + new data members. + (Sized_incremental_binary::output_section): New function. + (Sized_incremental_binary::inputs_reader): Add const. + (Sized_incremental_binary::symtab_reader): Add const. + (Sized_incremental_binary::relocs_reader): Add const. + (Sized_incremental_binary::got_plt_reader): Add const. + (Sized_incremental_binary::get_symtab_view): New function. + (Sized_incremental_binary::Inputs_reader): New typedef. + (Sized_incremental_binary::Input_entry_reader): New typedef. + (Sized_incremental_binary::do_check_inputs): Add cmdline parameter. + (Sized_incremental_binary::do_file_is_unchanged): Remove. + (Sized_incremental_binary::do_file_has_changed): New function. + (Sized_incremental_binary::do_init_layout): New function. + (Sized_incremental_binary::do_reserve_layout): New function. + (Sized_input_reader::Inputs_reader): Remove. + (Sized_input_reader::Input_entry_reader): Remove. + (Sized_input_reader::do_arg_serial): New function. + (Sized_input_reader::do_get_unused_symbol_count): New function. + (Sized_input_reader::do_get_unused_symbol): New function. + (Sized_incremental_binary::do_input_file_count): New function. + (Sized_incremental_binary::do_get_input_reader): Change signature; + use index instead of filename. + (Sized_incremental_binary::section_map_): New data member. + (Sized_incremental_binary::input_entry_readers_): New data member. + (class Sized_incr_relobj): New class. + (class Sized_incr_dynobj): New class. + (make_sized_incremental_object): New function. + (class Incremental_library): New class. + * layout.cc (Free_list::num_lists): New static data member. + (Free_list::num_nodes): New static data member. + (Free_list::num_removes): New static data member. + (Free_list::num_remove_visits): New static data member. + (Free_list::num_allocates): New static data member. + (Free_list::num_allocate_visits): New static data member. + (Free_list::init): New function. + (Free_list::remove): New function. + (Free_list::allocate): New function. + (Free_list::dump): New function. + (Free_list::print_stats): New function. + (Layout_task_runner::run): Resize output file for incremental updates. + (Layout::Layout): Initialize new data members. + (Layout::set_incremental_base): New function. + (Layout::init_fixed_output_section): New function. + (Layout::layout_eh_frame): Do not build .eh_frame_hdr section for + incremental updates. + (Layout::create_gold_note): Do not create gold note section for + incremental updates. + (Layout::set_segment_offsets): Do not recalculate RELRO alignment + for incremental updates. + (Layout::set_section_offsets): For incremental updates, allocate space + from free list. + (Layout::create_symtab_sections): Layout with offsets relative to + start of section; for incremental updates, allocate space from free + list. + (Layout::create_shdrs): For incremental updates, allocate space from + free list. + (Layout::finish_dynamic_section): For incremental updates, do not + check --as-needed (fixed in subsequent patch). + * layout.h (class Free_list): New class. + (Layout::set_incremental_base): New function. + (Layout::incremental_base): New function. + (Layout::init_fixed_output_section): New function. + (Layout::allocate): New function. + (Layout::incremental_base_): New data member. + (Layout::free_list_): New data member. + * main.cc (main): Print Free_list statistics. + * object.cc (Relobj::finalize_incremental_relocs): Add + clear_counts parameter; clear counts only when clear_counts is set. + (Sized_relobj::Sized_relobj): Initialize new base class. + (Sized_relobj::do_layout): Don't report special sections. + (Sized_relobj::do_for_all_local_got_entries): New function. + (Sized_relobj::write_local_symbols): Add symtab_off parameter; add + symtab_off to all symbol table offsets. + (Sized_relobj::do_get_global_symbol_counts): Add typename keyword. + * object.h (class Got_offset_list): Move to top of file. + (Object::Object): Allow case where input_file == NULL. + (Object::~Object): Likewise. + (Object::input_file): Assert that input_file != NULL. + (Object::lock): Allow case where input_file == NULL. + (Object::unlock): Likewise. + (Object::is_locked): Likewise. + (Object::token): Likewise. + (Object::release): Likewise. + (Object::is_incremental): New function. + (Object::get_mtime): New function. + (Object::for_all_local_got_entries): New function. + (Object::clear_view_cache_marks): Allow case where input_file == NULL. + (Object::set_is_in_system_directory): New function. + (Object::is_in_system_directory): New function. + (Object::do_is_incremental): New function. + (Object::do_get_mtime): New function. + (Object::do_for_all_local_got_entries): New function. + (Object::is_in_system_directory_): New data member. + (Relobj::finalize_incremental_relocs): Add clear_counts parameter. + (class Sized_relobj_base): New class. + (class Sized_relobj): Derive from Sized_relobj_base. + (class Sized_relobj::Symbols): Redeclare from base class. + (class Sized_relobj::local_got_offset_list): Remove. + (class Sized_relobj::Output_sections): Redeclare from base class. + (class Sized_relobj::do_for_all_local_got_entries): New function. + (class Sized_relobj::write_local_symbols): Add offset parameter. + (class Sized_relobj::local_symbol_offset_): Update comment. + (class Sized_relobj::local_dynsym_offset_): Update comment. + * options.cc (Input_arguments::add_file): Remove const. + * options.h (Input_file_argument::Input_file_argument): + Initialize arg_serial_ (all constructors). + (Input_file_argument::set_arg_serial): New function. + (Input_file_argument::arg_serial): New function. + (Input_file_argument::arg_serial_): New data member. + (Input_arguments::Input_arguments): Initialize file_count_. + (Input_arguments::add_file): Remove const. + (Input_arguments::number_of_input_files): New function. + (Input_arguments::file_count_): New data member. + (Command_line::number_of_input_files): Call + Input_arguments::number_of_input_files. + * output.cc (Output_segment_headers::Output_segment_headers): + Set current size. + (Output_section::Input_section::current_data_size): New function. + (Output_section::Output_section): Initialize new data members. + (Output_section::add_input_section): Don't do merge sections for + an incremental link; allocate space from free list for an + incremental update. + (Output_section::add_output_section_data): Allocate space from + free list for an incremental update. + (Output_section::update_data_size): New function. + (Output_section::set_fixed_layout): New function. + (Output_section::reserve): New function. + (Output_segment::set_section_addresses): Remove const. + (Output_segment::set_section_list_addresses): Remove const; allocate + space from free list for an incremental update. + (Output_segment::set_offset): Adjust size of RELRO segment for an + incremental update. + * output.h (Output_data::current_data_size): Move here from + child classes. + (Output_data::pre_finalize_data_size): New function. + (Output_data::update_data_size): New function. + (Output_section_headers::update_data_size): new function. + (Output_section_data_build::current_data_size): Move to Output_data. + (Output_data_strtab::update_data_size): New function. + (Output_section::current_data_size): Move to Output_data. + (Output_section::set_fixed_layout): New function. + (Output_section::has_fixed_layout): New function. + (Output_section::reserve): New function. + (Output_section::update_data_size): New function. + (Output_section::has_fixed_layout_): New data member. + (Output_section::free_list_): New data member. + (Output_segment::set_section_addresses): Remove const. + (Output_segment::set_section_list_addresses): Remove const. + * plugin.cc (Sized_pluginobj::do_for_all_local_got_entries): + New function. + * plugin.h (Sized_pluginobj::do_for_all_local_got_entries): + New function. + * readsyms.cc (Read_symbols::do_read_symbols): Add library + parameter when calling Add_symbols constructor; store argument + serial number for members of a lib group. + (Add_symbols::locks): Allow case where token == NULL. + (Add_symbols::run): Report libraries denoted by --start-lib/--end-lib. + (Read_member::~Read_member): New function. + (Read_member::is_runnable): New function. + (Read_member::locks): New function. + (Read_member::run): New function. + (Check_script::~Check_script): New function. + (Check_script::is_runnable): New function. + (Check_script::locks): New function. + (Check_script::run): New function. + (Check_library::~Check_library): New function. + (Check_library::is_runnable): New function. + (Check_library::locks): New function. + (Check_library::run): New function. + * readsyms.h (Add_symbols::Add_symbols): Add library parameter. + (Add_symbols::library_): New data member. + (class Read_member): New class. + (class Check_script): New class. + (class Check_library): New class. + * reloc.cc (Read_relocs::is_runnable): Allow case where + token == NULL. + (Read_relocs::locks): Likewise. + (Scan_relocs::locks): Likewise. + (Relocate_task::locks): Likewise. + (Sized_relobj::do_scan_relocs): Tell finalize_incremental_relocs + to clear counters. + (Sized_relobj::incremental_relocs_scan): Fix comment. + (Sized_relobj::do_relocate): Pass output file offset to + write_local_symbols. + (Sized_relobj::incremental_relocs_write_reltype): Use reloc_size + from class declaration. + * script.cc (read_input_script): Allocate Script_info; pass + argument serial number to report_script. + * script.h (class Script_info): Move to incremental.h. + * symtab.cc (Symbol_table::add_from_incrobj): New function. + * symtab.h (Symbol_table::add_from_incrobj): New function. + (Symbol_table::set_file_offset): New function. + +2011-04-05 Cary Coutant + + * incremental-dump.cc (dump_incremental_inputs): Change signature + to take a Sized_incremental_binary; change caller. Use readers + in Sized_incremental_binary. + * incremental.cc + (Sized_incremental_binary::find_incremental_inputs_sections): + Rename do_find_incremental_inputs_sections to this. + (Sized_incremental_binary::setup_readers): New function. + (Sized_incremental_binary::do_check_inputs): Check + has_incremental_info_ flag; move setup code to setup_readers; + use input readers. + (Sized_incremental_binary::do_file_is_unchanged): New function. + (Sized_incremental_binary::do_get_input_reader): New function. + * incremental.h (class Incremental_binary): Move to end of file. + (Incremental_binary::file_is_unchanged): New function. + (Incremental_binary::do_file_is_unchanged): New function. + (Incremental_binary::Input_reader): New class. + (Incremental_binary::get_input_reader): New function. + (class Sized_incremental_binary): Move to end of file. + (Sized_incremental_binary::Sized_incremental_binary): Setup the + input section reader classes. + (Sized_incremental_binary::has_incremental_info): New function. + (Sized_incremental_binary::inputs_reader): New function. + (Sized_incremental_binary::symtab_reader): New function. + (Sized_incremental_binary::relocs_reader): New function. + (Sized_incremental_binary::got_plt_reader): New function. + (Sized_incremental_binary::do_file_is_unchanged): New function. + (Sized_incremental_binary::Sized_input_reader): New class. + (Sized_incremental_binary::get_input_reader): New function. + (Sized_incremental_binary::find_incremental_inputs_sections): + Rename do_find_incremental_inputs_sections to this. + (Sized_incremental_binary::setup_readers): New function. + (Sized_incremental_binary::has_incremental_info_): New data member. + (Sized_incremental_binary::inputs_reader_): New data member. + (Sized_incremental_binary::symtab_reader_): New data member. + (Sized_incremental_binary::relocs_reader_): New data member. + (Sized_incremental_binary::got_plt_reader_): New data member. + (Sized_incremental_binary::current_input_file_): New data member. + +2011-04-05 Paul Pluzhnikov + + PR gold/12640 + * dwarf_reader.cc (Sized_dwarf_line_info): Fix vector bounds + violation. + +2011-03-30 Cary Coutant + + * archive.cc (Archive::include_member): Adjust call to report_object. + (Add_archive_symbols::run): Add script_info to call to + report_archive_begin. + (Lib_group::include_member): Adjust call to report_object. + (Add_lib_group_symbols::run): Adjust call to report_object. + * incremental-dump.cc (dump_incremental_inputs): Remove unnecessary + blocks. Add object count for script input files. + * incremental.cc (Incremental_inputs::report_archive_begin): Add + script_info parameter; change all callers. + (Incremental_inputs::report_object): Add script_info parameter; + change all callers. + (Incremental_inputs::report_script): Store backpointer to + incremental info entry. + (Output_section_incremental_inputs::set_final_data_size): Record + additional information for scripts. + (Output_section_incremental_inputs::write_info_blocks): Likewise. + * incremental.h (Incremental_script_entry::add_object): New function. + (Incremental_script_entry::get_object_count): New function. + (Incremental_script_entry::get_object): New function. + (Incremental_script_entry::objects_): New data member; adjust + constructor. + (Incremental_inputs::report_archive_begin): Add script_info parameter. + (Incremental_inputs::report_object): Add script_info parameter. + (Incremental_inputs_reader::get_object_count): New function. + (Incremental_inputs_reader::get_object_offset): New function. + * options.cc (Input_arguments::add_file): Return reference to + new input argument. + * options.h (Input_argument::set_script_info): New function. + (Input_argument::script_info): New function. + (Input_argument::script_info_): New data member; adjust all + constructors. + (Input_file_group::add_file): Return reference to new input argument. + (Input_file_lib::add_file): Likewise. + (Input_arguments::add_file): Likewise. + * readsyms.cc (Add_symbols::run): Adjust call to report_object. + * script.cc (Parser_closure::Parser_closure): Add script_info + parameter; adjust all callers. + (Parser_closure::script_info): New function. + (Parser_closure::script_info_): New data member. + (read_input_script): Report scripts earlier to incremental info. + (script_add_file): Set script_info in Input_argument. + (script_add_library): Likewise. + * script.h (Script_options::Script_info): Rewrite class. + +2011-03-29 Cary Coutant + + * archive.cc (Library_base::should_include_member): Move + method here from class Archive. + (Archive::Archive): Initialize base class. + (Archive::should_include_member): Move to base class. + (Archive::do_for_all_unused_symbols): New function. + (Add_archive_symbols::run): Remove redundant access to + incremental_inputs. + (Lib_group::Lib_group): Initialize base class. + (Lib_group::do_filename): New function. + (Lib_group::include_member): Pass pointer to Lib_group to + report_object. + (Lib_group::do_for_all_unused_symbols): New function. + (Add_lib_group_symbols::run): Report archive information for + incremental links. + * archive.h (class Library_base): New base class. + (class Archive): Derive from Library_base. + (Archive::filename): Move to base class. + (Archive::set_incremental_info): Likewise. + (Archive::incremental_info): Likewise. + (Archive::Should_include): Likewise. + (Archive::should_include_member): Likewise. + (Archive::Armap_entry): Remove. + (Archive::Unused_symbol_iterator): Remove. + (Archive::unused_symbols_begin): Remove. + (Archive::unused_symbols_end): Remove. + (Archive::do_filename): New function. + (Archive::do_get_mtime): New function. + (Archive::do_for_all_unused_symbols): New function. + (Archive::task_): Move to base class. + (Archive::incremental_info_): Likewise. + (class Lib_group): Derive from Library_base. + (Lib_group::do_filename): New function. + (Lib_group::do_get_mtime): New function. + (Lib_group::do_for_all_unused_symbols): New function. + (Lib_group::task_): Move to base class. + * dynobj.cc (Sized_dynobj::do_for_all_global_symbols): New + function. + * dynobj.h (Sized_dynobj::do_for_all_global_symbols): New + function. + * incremental.cc (Incremental_inputs::report_archive_begin): + Use Library_base; call library's get_mtime; add incremental inputs + entry before members. + (class Unused_symbol_visitor): New class. + (Incremental_inputs::report_archive_end): Use Library_base; use + visitor class to record unused symbols; don't add incremental inputs + entry after members. + (Incremental_inputs::report_object): Use Library_base. + * incremental.h + (Incremental_archive_entry::Incremental_archive_entry): Remove + unused Archive parameter. + (Incremental_inputs::report_archive_begin): Use Library_base. + (Incremental_inputs::report_archive_end): Likewise. + (Incremental_inputs::report_object): Likewise. + * object.cc (Sized_relobj::do_for_all_global_symbols): New + function. + * object.h (Object::for_all_global_symbols): New function. + (Object::do_for_all_global_symbols): New function. + (Sized_relobj::do_for_all_global_symbols): New function. + * plugin.cc (Sized_pluginobj::do_for_all_global_symbols): New + function. + * plugin.h (Sized_pluginobj::do_for_all_global_symbols): New + function. + +2011-03-27 Ian Lance Taylor + + * archive.cc (Archive::interpret_header): Return -1 if something + goes wrong. Change callers accordingly. + +2011-03-25 Cary Coutant + + * testsuite/Makefile.am (final_layout.stdout): Use -n option with nm. + * testsuite/Makefile.in: Regenerate. + +2011-03-23 Rafael Ávila de Espíndola + + * plugin.cc (get_view): New. + (Plugin::load): Pass get_view to the plugin. + (Plugin_manager::get_view): New. + +2011-03-21 Ian Lance Taylor + + * testsuite/final_layout.sh: Rewrite to not use dc. + * testsuite/relro_test.sh: Fail if dc is not present. + +2011-03-21 Sriraman Tallam + + * testsuite/icf_safe_so_test.sh: Add #!/bin/sh to start. + Change == to -eq. + * testsuite/icf_string_merge_test.sh: Add #!/bin/sh to start. + * testsuite/icf_safe_test.sh: Add #!/bin/sh to start. + Change == to -eq. + * testsuite/icf_sht_rel_addend_test.sh: Add #!/bin/sh to start. + * testsuite/icf_preemptible_functions_test.sh: Add #!/bin/sh to start. + +2011-03-14 Ian Lance Taylor + + * script-sections.cc (Sort_output_sections::script_compare): + Rename from is_before, change return type. + (Sort_output_sections::operator()): Adjust accordingly. + +2011-03-11 Jeffrey Yasskin + + PR gold/12572 + * testsuite/odr_violation2.cc: Add comment to make all error line + numbers double digits. + * testsuite/debug_msg.sh: Adjust expected errors. + +2011-03-09 Jeffrey Yasskin + + * dwarf_reader.cc (Sized_dwarf_line_info): Include all lines, + but mark earlier ones as non-canonical + (offset_to_iterator): Update search target and example + (do_addr2line): Return extra lines in a vector* + (format_file_lineno): Extract from do_addr2line + (one_addr2line): Add vector* out-param + * dwarf_reader.h (Offset_to_lineno_entry): New field recording + when a lineno entry appeared last for its instruction + (Dwarf_line_info): Add vector* out-param + * object.cc (Relocate_info): Pass NULL for the vector* out-param + * symtab.cc (Odr_violation_compare): Include the lineno in the + comparison again. + (linenos_from_loc): New. Combine the canonical line for an + address with its other lines. + (True_if_intersect): New. Helper functor to make + std::set_intersection a query. + (detect_odr_violations): Compare sets of lines instead of just + one line for each function. This became less deterministic, but + has fewer false positives. + * symtab.h: Declarations. + * testsuite/Makefile.am (odr_violation2.o): Compile with -O2 to + mix an optimized and non-optimized object in the same binary + (odr_violation2.so): Same. + * testsuite/Makefile.in: Regenerate from Makefile.am. + * testsuite/debug_msg.cc (main): Make OdrDerived classes. + * testsuite/debug_msg.sh: Update line numbers and add + assertions. + * testsuite/odr_violation1.cc: Use OdrDerived, in a + non-optimized context. + * testsuite/odr_violation2.cc: Make sure Ordering::operator() + isn't inlined, and use OdrDerived in an optimized context. + * testsuite/odr_header1.h: Defines OdrDerived, where + optimization will change the + first-instruction-in-the-destructor's file and line number. + * testsuite/odr_header2.h: Defines OdrBase. + +2011-03-09 Ian Lance Taylor + + * fileread.cc (File_read::clear_views): Don't delete the whole + file view. + +2011-03-08 Ian Lance Taylor + + PR gold/12525 + * fileread.cc: #include . + (GOLD_IOV_MAX): Define. + (File_read::read_multiple): Limit number of entries by iov_max. + * fileread.h (class File_read): Always set max_readv_entries to + 128. + +2011-03-07 Ian Lance Taylor + + PR gold/12525 + * options.h (class General_options): Add -dy and -dn. + +2011-03-02 Cary Coutant + + * testsuite/script_test_9.t: Add TLS segment. + +2011-03-02 Simon Baldwin + + * configure.ac: Add check for gnu_indirect_function support in + the toolchain building binutils. + * configure: Rebuild. + +2011-02-18 Rafael Ávila de Espíndola + + * symtab.cc (Symbol::should_add_dynsym_entry) Return false for + plugin only symbols. + (Symbol_table::sized_finalize_symbol) Mark symbol only present + in plugin files as not needed in the symbol table. + +2011-02-11 Sriraman Tallam + + * output.cc (Output_section::add_input_section): Delay fill + generation for section ordering. + +2011-02-09 Ian Lance Taylor + + PR gold/12316 + * object.h (class Sized_relobj): Remove clear_local_symbols. + * reloc.cc (Sized_relobj::do_relocate): Don't call + clear_local_symbols. + +2011-02-08 Rafael Ávila de Espíndola + + * plugin.cc (is_visible_from_outside): Return true for symbols + in the -u option. + +2011-02-04 Jeffrey Yasskin + + * symtab.cc (Odr_violation_compare::operator()): Sort by just the + filename. + +2011-02-02 Sriraman Tallam + + * icf.h (is_section_foldable_candidate): Change type of parameter + to std::string. + * icf.cc (Icf::find_identical_sections): Change type of local variable + section_name to be std::string. + (is_function_ctor_or_dtor): Change type of parameter to std::string. + +2011-01-25 Ian Lance Taylor + + * script.cc (script_add_extern): Rewrite to use + add_symbol_reference. + +2011-01-25 Doug Kwan + + * icf.cc (get_section_contents): Always lock section's object. + +2011-01-24 Ian Lance Taylor + + * options.h (class General_options): Accept + --no-detect-odr-violations. + +2011-01-24 Ian Lance Taylor + + * version.cc (version_string): Bump to 1.11. + +2011-01-24 Ian Lance Taylor + + * plugin.cc (class Plugin_rescan): Define new class. + (Plugin_manager::claim_file): Set any_claimed_. + (Plugin_manager::save_archive): New function. + (Plugin_manager::save_input_group): New function. + (Plugin_manager::all_symbols_read): Create Plugin_rescan task if + necessary. + (Plugin_manager::new_undefined_symbol): New function. + (Plugin_manager::rescan): New function. + (Plugin_manager::rescannable_defines): New function. + (Plugin_manager::add_input_file): Set any_added_. + * plugin.h (class Plugin_manager): define new fields rescannable_, + undefined_symbols_, any_claimed_, and any_added_. Declare + Plugin_rescan as friend. Declare new functions. + (Plugin_manager::Rescannable): Define type. + (Plugin_manager::Rescannable_list): Define type. + (Plugin_manager::Undefined_symbol_list): Define type. + (Plugin_manager::Plugin_manager): Initialize new fields. + * archive.cc (Archive::defines_symbol): New function. + (Add_archive_symbols::run): Pass archive to plugins if any. + * archive.h (class Archive): Declare defines_symbol. + * readsyms.cc (Input_group::~Input_group): New function. + (Finish_group::run): Pass input_group to plugins if any. + * readsyms.h (class Input_group): Declare destructor. + * symtab.cc (add_from_object): Pass undefined symbol to plugins if + any. + +2011-01-10 Ian Lance Taylor + + * layout.cc (Layout::layout_eh_frame): Mark a writable .eh_frame + section as relro. + (Layout::set_segment_offsets): Reset increase_relro before calling + set_section_addresses a second time. + +2011-01-04 Cary Coutant + + * script-sections.cc (Sort_output_sections::operator()): Sort TLS + sections before NOBITS sections. + +2011-01-01 H.J. Lu + + * version.cc (print_version): Update copyright to 2011. + +2010-12-23 Cary Coutant + + * output.h (Output_data_reloc::add_output_section): Pass OD instead + of OS to this->add. Add OD parameter to second form of the function. + +2010-12-20 Ian Lance Taylor + + * dwarf_reader.cc (Sized_dwarf_line_info::read_lines): Only keep + second of two consecutive entries with same offset. + +2010-12-16 Ralf Wildenhues + + * testsuite/Makefile.am (ifuncmain2static_LDADD) + (ifuncmain2_LDADD, ifuncmain4static_LDADD, ifuncmain4_LDADD) + (ifuncmain7static_LDADD, ifuncmain7_LDADD): New empty variables, + to avoid unneeded links against $(LDADD). + * testsuite/Makefile.in: Regenerate. + +2010-12-15 Ian Lance Taylor + + PR gold/12324 + * x86_64.cc (Target_x86_64::Scan::check_non_pic): Give an error + for R_X86_64_32 and R_X86_64_PC32. + * testsuite/Makefile.am (ver_matching_def.so): Depend on and use + ver_matching_def_pic.o. + (ver_matching_def_pic.o): New target. + +2010-12-14 Ralf Wildenhues + + * fileread.cc (file_counts_lock, file_counts_initialize_lock) + (total_mapped_bytes, current_mapped_bytes, maximum_mapped_bytes): + Move definition before File_read::View member definitions. + (File_read::View::~View): Initialize and hold lock before + updating current_mapped_bytes. + +2010-12-14 Ralf Wildenhues + + * dwarf_reader.cc: Remove outdated comment. + * gold-threads.cc: Fix typo in error message. + * archive.cc: Fix typos in comments. + * archive.h: Likewise. + * arm-reloc-property.cc: Likewise. + * arm-reloc-property.h: Likewise. + * arm-reloc.def: Likewise. + * arm.cc: Likewise. + * attributes.h: Likewise. + * cref.cc: Likewise. + * ehframe.cc: Likewise. + * fileread.h: Likewise. + * gold.h: Likewise. + * i386.cc: Likewise. + * icf.cc: Likewise. + * incremental.h: Likewise. + * int_encoding.cc: Likewise. + * layout.h: Likewise. + * main.cc: Likewise. + * merge.h: Likewise. + * object.cc: Likewise. + * object.h: Likewise. + * options.cc: Likewise. + * readsyms.cc: Likewise. + * reduced_debug_output.cc: Likewise. + * reloc.cc: Likewise. + * script-sections.cc: Likewise. + * sparc.cc: Likewise. + * symtab.h: Likewise. + * target-reloc.h: Likewise. + * target.cc: Likewise. + * target.h: Likewise. + * timer.cc: Likewise. + * timer.h: Likewise. + * x86_64.cc: Likewise. + +2010-12-09 Cary Coutant + + * layout.cc (Layout::layout_gnu_stack): Add warnings for executable + stack. + * layout.h (Layout::layout_gnu_stack): Add pointer to Object + parameter; change all callers. + * object.cc (Sized_relobj::do_layout): Adjust call to layout_gnu_stack. + * options.h (warn_execstack): New option. + +2010-12-07 Doug Kwan + + * arm.cc (Target_arm::Scan::get_reference_flags): Treat R_ARM_PREL31 + like function call relocations. + +2010-12-07 Ian Lance Taylor + + * archive.cc (Archive::get_elf_object_for_member): Permit + punconfigured to be NULL. + (Archive::read_symbols): Pass NULL to get_elf_object_for_member. + (Archive::include_member): Pass NULL to get_elf_object_for_member + if we searched for the archive and this is the first included + object. + +2010-12-01 Ian Lance Taylor + + * dwarf_reader.h (class Sized_dwarf_line_info): Add + track_relocs_type_ field. + * dwarf_reader.cc (Sized_dwarf_line_info::Sized_dwarf_line_info): + Set track_relocs_type_. + (Sized_dwarf_line_info::process_one_opcode): Ignore the section + contents when using RELA relocs. + (Sized_dwarf_line_info::read_relocs): Add the reloc addend to + reloc_map_. + * reloc.cc (Track_relocs::next_addend): New function. + * reloc.h (class Track_relocs): Declare next_addend. + +2010-12-01 Ian Lance Taylor + + * testsuite/icf_virtual_function_folding_test.cc (class Bar): Add + virtual destructor. + +2010-12-01 Ian Lance Taylor + + * README: Update compilers known to work and fail. + +2010-11-23 Matthias Klose + + * configure.in: For --enable-gold, handle value `default' instead of + `both*'. Always install ld as ld.bfd, install as ld if gold is + not the default. + * configure: Regenerate. + +2010-11-18 Doug Kwan + + * expression.cc (BINARY_EXPRESSION): Initialize left_alignment + and right_alignment to be zero. Store result alignment only if it is + greater than existing alignment. + +2010-11-16 Cary Coutant + + PR gold/12220 + * dwarf_reader.cc (Sized_dwarf_line_info::Sized_dwarf_line_info): + Check for ".zdebug_line". + +2010-11-16 Doug Kwan + Cary Coutant + + * output.h (Output_segment::set_section_addresses): Pass increase_relro + by reference; adjust all callers. + * output.cc (Output_segment::set_section_addresses): Adjust references + to increase_relro. Add padding to *increase_relro when ORDER_RELRO_LAST + list is empty. + (Output_segment::set_offset): Assert if PT_GNU_RELRO segment does not + end at page boundary. + +2010-11-16 Cary Coutant + + PR gold/12220 + * layout.cc (Layout::choose_output_section): Transform names of + compressed sections even when using a script with a SECTIONS clause. + (Layout::output_section_name): Remove code to transform + compressed debug section names. + * output.cc (Output_section::add_input_section): Use uncompressed + section size when tracking input sections. + +2010-11-11 Richard Sandiford + + * symtab.h (Symbol::NON_PIC_REF): Remove. + (Symbol::RELATIVE_REF, Symbol::TLS_REF): New Reference_flags. + (Symbol::FUNCTION_CALL): Renumber. Reword comment. + (Symbol::needs_dynamic_reloc): Don't check NON_PIC_REF. + (Symbol::use_plt_offset): Take a flags argument and pass it + directly to needs_dynamic_reloc. Restrict check for undefined + weak symbols to function calls. + * arm.cc (Target_arm::Scan::get_reference_flags): New function. + (Target_arm::Scan::global): Use it. + (Target_arm::Scan::scan_reloc_for_stub): Likewise. + (Target_arm::Relocate::relocate): Likewise. + (Target_arm::Relocate::should_apply_static_reloc): Replace flags + parameter with an r_type parameter. Use get_reference_flags + to get the flags. + (Target_arm::Relocate::relocate): Update accordingly. + * i386.cc (Target_i386::Scan::get_reference_flags): New function. + (Target_i386::Scan::reloc_needs_plt_for_ifunc): Use it. + (Target_i386::Scan::global): Likewise. + (Target_i386::Relocate::relocate): Likewise. + (Target_i386::Relocate::should_apply_static_reloc): Replace flags + parameter with an r_type parameter. Use get_reference_flags + to get the flags. + (Target_i386::Relocate::relocate): Update accordingly. + * powerpc.cc (Target_powerpc::Scan::get_reference_flags): New function. + (Target_powerpc::Scan::global): Use it. + (Target_powerpc::Scan::scan_reloc_for_stub): Likewise. + (Target_powerpc::Relocate::relocate): Likewise. + * sparc.cc (Target_sparc::Scan::get_reference_flags): New function. + (Target_sparc::Scan::global): Use it. + (Target_sparc::Scan::scan_reloc_for_stub): Likewise. + (Target_sparc::Relocate::relocate): Likewise. + * x86_64.cc (Target_x86_64::Scan::get_reference_flags): New function. + (Target_x86_64::Scan::reloc_needs_plt_for_ifunc): Use it. + (Target_x86_64::Scan::global): Likewise. + (Target_x86_64::Relocate::relocate): Likewise. + +2010-11-08 Doug Kwan + Cary Coutant + + * arm.cc (Arm_exidx_merge_section::build_contents): New method. + (Arm_exidx_merge_section::section_contents_): New data member. + (Arm_input_section::Arm_input_section): Initialize original_contents_. + (Arm_input_section::~Arm_input_section): De-allocate memory. + (Arm_input_section::original_contents_): New data member. + (Arm_exidx_fixup::process_exidx_section): Pass EXIDX section contents + in parameters instead of calling Object::section_contents without + locking. + (Arm_output_section::group_section): New parameter TASK. Pass it + to callees that need locking objects. + (Arm_output_section::fix_exidx_coverage): New parameter TASK. Use it + to lock EXIDX input sections. Fix a formatting issue. Call + Arm_exidx_merged_section::build_contents to create merged section + contents. + (Arm_output_section::create_stub_group): New parameter TASK. Use it + to lock object of stub table owner. + (Arm_exidx_input_section::Arm_exidx_input_section): Add new parameter + TEXT_SIZE to initialize data member TEXT_SIZE_. + (Arm_exidx_input_section::addralign): Fix typo in comment. + (Arm_exidx_input_section::text_size): New method. + (Target_arm::do_relax): New parameter TASK. Pass it to callees + that require locking objects. Lock objects before scanning for stubs + and updating local symbols. + (Arm_input_section::init): Copy contents of original + input section. + (Arm_input_section::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 + size without calling Object::section_size(). + (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 + 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 + to Arm_exidx_input_section constructor. + (Arm_relobj::do_read_symbols): Fix memory leak. Fix a formatting issue. + (Arm_dynobj::do_read_symbols): Fix memory leak. + * layout.cc (Layout::finalize): Pass TASK to Target::relax(). + * target.h: (class Task): Add forward declaration. + (Target::relax): Add new parameter TASK and pass it to + Target::do_relax(). + (Target::do_relax):: New parameter TASK. Fix a formatting issue. + +2010-11-05 Cary Coutant + + PR gold/10708 + * copy-relocs.cc (Copy_relocs::emit_copy_reloc): Hold a lock on the + object when reading from the file. + * gold.cc (queue_middle_tasks): Hold a lock on the object when doing + second layout pass. + * icf.cc (preprocess_for_unique_sections): Hold a lock on the object + when reading section contents. + (get_section_contents): Likewise. + (icf::find_identical_sections): Likewise. + * mapfile.cc (Mapfile::print_discarded_sections): Hold a lock on the + object when reading from the file. + * plugin.cc (Plugin_manager::layout_deferred_objects): Hold a lock on + the object when doing deferred section layout. + +2010-11-03 Nick Clifton + + PR gold/12001 + * script.h (class Symbol_assignment: name): New member. Returns + the name of the symbol. + * scrfipt.cc (Script_options::is_pending_assignment): New member. + Returns true if the given symbol name is on the list of + assignments wating to be processed. + * archive.cc (should_incldue_member): If the symbol is undefined, + check to see if it is on the list of symbols pending assignment. + +2010-11-03 Ryan Mansfield + + * script-sections.cc (Script_sections::find_memory_region): Check + for a NULL output section pointer. + +2010-10-29 Doug Kwan + + * arm.cc (Arm_outout_section::fix_exidx_coverage): Adjust call to + Output_section::add_relaxed_input_section. + * output.cc (Output_section::add_relaxed_input_section): Add new + arguments LAYOUT and NAME. Set section order index. + (Output_section::convert_input_sections_in_list_to_relaxed_sections): + Copy section order index. + * output.h (Output_section::add_relaxed_input_section): Add new + arguments LAYOUT and NAME. + +2010-10-29 Viktor Kutuzov + + * testsuite/Makefile.am: Move gcctestdir/ld rule to + NATIVE_OR_CROSS_LINKER. + * testsuite/Makefile.in: Regenerate. + +2010-10-20 Doug Kwan + + * arm.cc (Arm_relobj::do_read_symbols): Warn about ARM EXIDX sections + without SHF_LINK_ORDER flags. + * layout.cc (Layout::choose_output_section): Do not filter + SHF_LINK_ORDER flag in a relocatable link. + +2010-10-17 Cary Coutant + + * output.h (Output_segment::set_section_addresses): Change function + signature. Update all callers. + * output.cc (Output_segment::is_first_section_relro): Ignore TLS + sections. + (Output_segment::set_section_addresses): Align after last TLS + section. Add padding before last relro section instead of after. + +2010-10-17 Doug Kwan + + * gold/arm.cc (Target_arm::got_section): Use correct order and set + GOT output section to be writable. + +2010-10-14 Cary Coutant + + * 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. + +2010-10-12 Viktor Kutuzov + + * script-sections.h (class Script_sections): Make + Sections_elements typedef public. + * script-sections.cc (class Sort_output_sections): Add elements_ + field. Add constructor which sets it; change all callers. + (Sort_output_sections::is_before): New function. + (Sort_output_sections::operator()): Call is_before. + * configure.ac (NATIVE_OR_CROSS_LINKER): New automake + conditional. + * testsuite/script_test_10.sh: New test. Test script section + order. + * testsuite/script_test_10.t: Likewise. + * testsuite/script_test_10.s: Likewise. + * testsuite/Makefile.am: Wrap the cross linker tests and the + common tests into NATIVE_OR_CROSS_LINKER. + (check_SCRIPTS): Add script_test_10.sh. + (check_DATA): Add script_test_10.stdout. + (script_test_10.o, script_test_10): New targets. + (script_test_10.stdout): New target. + * configure, testsuite/Makefile.in: Regenerate. + +2010-10-12 Viktor Kutuzov + + * arm.cc (Target_arm::Scan::local): Report the unsupported reloc + error for the deprecated relocations. + (Target_arm::Scan::global): Likewise. + (Target_arm::Relocate::relocate): Likewise. + +2010-10-12 Richard Sandiford + + * fileread.cc (Input_file::find_file): Initialize *found_name + and *namep when using the fallback search for case 4. + +2010-10-11 Cary Coutant + + * options.h (class General_options): Redefine -z lazy as an alias for + the negation of -z now. + +2010-10-11 Ian Lance Taylor + + * resolve.cc (symbol_to_bits): Report the value of the unsupported + binding. + +2010-10-06 Nick Clifton + + * script-sections.cc(class Memory_region): Remove + current_lma_offset_ field. Rename current_vma_offset_ to + current_offset_. Add last_section_ field. + (Memory_region::get_current_vma_address): Rename to + get_current_address. + (Memory_region::get_current_lma_address): Delete. + (Memory_region::increment_vma_offset): Rename to + increment_offset. + (Memory_region::increment_lma_offset): Delete. + (Memory_region::attributes_compatible): New method. Returns + true if the provided section is compatible with the region. + (Memory_region::get_last_section): New method. Returns the last + section to use the region. + (Memory_region::set_last_section): New method. Stores the last + section to use the region. + (Script_sections::block_in_region): New method. Returns true if + a block of memory is contained within a region. + (Script_sections::find_memory_region): New method. Locates a + memory region to be used to set a VMA or LMA address. + (Output_section_definition::set_section_addresses): Add code to + check for addresses set by memory regions. + (Output_segment::set_section_addresses): Remove memory region + walking code. + (Script_sections::create_segment): Add a warning if a header + segment is created outside of any region. + * script-sections.h (class Script_sections): Add prototypes for + find_memory_region and block_in_region methods. + * testsuite/memory_test.s: Use .long instead of .word. + * testsuite/memory_test.t: Add some more output sections. + * testsuite/memory_test.sh: Update expected output. + +2010-10-02 Doug Kwan + + * symtab.cc (Symbol_table::Symbol_table_hash::operator()): Move + defintion to symtab.h + * symtab.h (Symbol_table::Symbol_table_hash::operator()): Change + declaration to defintion. + +2010-10-01 Nick Clifton + + * expression.cc (eval): Replace dummy argument with NULL. + (eval_maybe_dot): Check for a NULL result section pointer. + (Symbol_expression::value): Likewise. + (Dot_expression::value): Likewise. + (BINARY_EXPRESSION): Likewise. + (Max_expression::value): Likewise. + (Min_expression::value): Likewise. + (Absolute_expression::value): Likewise. + (Addr_expression::value_from_output_section): Likewise. + (Loaddddr_expression::value_from_output_section): Likewise. + (Segment_start_expression::value): Likewise. + * script-sections.cc + (Sections_elememt_dot_assignment::finalize_symbols): Replace dummy + argument with NULL. + (Sections_elememt_dot_assignment::set_section_addresses): + Likewise. + (Output_data_expression::do_write_to_buffer): Likewise. + (Output_section_definition::finalize_symbols): Likewise. + (Output_section_definition::set_section_addresses): Likewise. + +2010-09-30 Doug Kwan + + * gold/testsuite/arm_branch_out_of_range.sh: Fix broken tests. + +2010-09-28 Sriraman Tallam + + * target.h (Target::can_icf_inline_merge_sections): New virtual + function. + * x86_64.cc (Target__x86_64::can_icf_inline_merge_sections): New + virtual function. + * i386.cc (Target_i386::can_icf_inline_merge_sections): New + virtual function. + * icf.cc (get_section_contents): Inline merge sections only when + target allows it. + +2010-09-27 Ralf Wildenhues + + * configure: Regenerate. + +2010-09-17 Ian Lance Taylor + + * testsuite/memory_test.sh: Adjust for change of 2010-09-10. + * testsuite/Makefile.am (memory_test.o): New target. + (memory_test): Depend on memory_test.o, gcctestdir/ld, and + memory_test.t. + * testsuite/Makefile.in: Rebuild. + +2010-09-17 Doug Kwan + + * arm.cc (Target_arm::Relocate::relocate): Ignore symbol type and + defintion if relocation uses GOT entries of the symbol. + * testsuite/icf_safe_test.sh: Fix test. + * testsuite/icf_safe_so_test.sh: Fix test. + +2010-09-16 Cary Coutant + + * script_sections.cc (class Memory_region): Remove "NULL" from + vector initializations. + +2010-09-15 Cary Coutant + + * incremental.cc (Output_section_incremental_inputs::write_info_blocks): + Resolve forwarding symbols. + +2010-09-15 Doug Kwan + + * gold/testsuite/script_test_3.t: Add ARM special sections. + * gold/testsuite/script_test_4.t: Same. + * gold/testsuite/script_test_5.t: Same. + * gold/testsuite/script_test_6.t: Same. + * gold/testsuite/script_test_7.t: Same. + * gold/testsuite/script_test_7.t: Same. + * gold/testsuite/thumb_blx_out_of_range.s: Fix instruction alignment. + +2010-09-14 Cary Coutant + + * x86_64.cc (Target_x86_64::saw_tls_block_reloc_): Remove member. + (Target_x86_64::Relocate::relocate_tls): Replace check for + saw_tls_block_reloc_ with test for executable section. + +2010-09-12 Cary Coutant + + * symtab.h (Symbol::needs_dynamic_reloc): Non-PIC calls from + position-independent executables to shared libraries need dynamic + relocations. + (Symbol::may_need_copy_reloc): Do not generate COPY relocs in + position-independent executables. + * testsuite/Makefile.am (two_file_mixed_pie_test): New test. + * testsuite/Makefile.in: Regenerate. + +2010-09-10 Nick Clifton + + PR gold/11997 + * testsuite/memory_test.t: Discard any sections that are not + needed. + +2010-09-09 H.J. Lu + + PR gold/11996 + * object.cc (Sized_relobj::do_finalize_local_symbols): Remove + "This::" to work around a bug in gcc 4.2. + + * testsuite/ifuncmain7.c (foo_ifunc): Add __attribute__ ((used)). + +2010-09-09 Rafael Espindola + + * layout.cc (Layout::attach_allocated_section_to_segment): Don't put + sections with different PF_X flags in the same segment. + (Layout::find_first_load_seg): Search all segments to find the first + one. + * options.h (rosegment): New. + +2010-09-08 Rafael Espindola + + * layout.cc (Layout::set_segment_offsets): Always advance to a new page. + +2010-09-08 Doug Kwan + + * arm.cc (Arm_exidx_cantunwind::do_print_to_mapfile): New method. + (Arm_relobj::do_relocate_sections): Add new parameter for output + file to match the parent. + (Target_arm::scan_reloc_section_for_stubs): Use would-be final values + of local symbols instead of input values. Update code to track + changes in gold::relocate_section. + * object.cc (Sized_relobj::compute_final_local_value): New methods. + (Sized_relobj::compute_final_local_value_internal): New methods. + (Sized_relobj::do_finalize_local_symbols): Move code from loop + body into private version of Sized_relobj::compute_final_local_value. + Call the inline method. + * object.h (Symbol_value::Symbol_value): Define destructor. Free + merged symbol value if there is one. + (Symbol_value::has_output_value): New method defintiion. + (Sized_relobj::Compute_final_local_value_status): New enum type. + (Sized_relobj::compute_final_local_value): New methods. + (Sized_relobj::compute_final_local_value_internal): New methods. + * Makefile.am (check_SCRIPTS): Add arm_branch_out_of_range.sh + and arm_cortex_a8.sh. + (thumb_bl_out_of_range_local, arm_cortex_a8_b_cond, arm_cortex_a8_bl, + arm_cortex_a8_blx, arm_cortex_a8_local, arm_corte_a8_local_reloc): + New tests. + * Makefile.in: Regenerate. + * testsuite/arm_bl_out_of_range.s: Update test. + * testsuite/thumb_bl_out_of_range.s: Ditto. + * testsuite/thumb_blx_out_of_range.s: Ditto. + * testsuite/arm_branch_out_of_range.sh: New file. + * testsuite/arm_cortex_a8.sh: Ditto. + * testsuite/arm_cortex_a8_b.s: Ditto. + * testsuite/arm_cortex_a8_b_cond.s: Ditto. + * testsuite/arm_cortex_a8_b_local.s: Ditto. + * testsuite/arm_cortex_a8_bl.s: Ditto. + * testsuite/arm_cortex_a8_blx.s: Ditto. + * testsuite/arm_cortex_a8_local.s: Ditto. + * testsuite/arm_cortex_a8_local_reloc.s: Ditto. + * testsuite/thumb_bl_out_of_range_local.s: Ditto. + +2010-09-08 Rafael Espindola + + * Makefile.am (memory_test.stdout): Run readelf with -W. + * Makefile.in: Regenerate. + * testsuite/memory_test.sh: Make the regexps accept both 32 and + 64 bit output. + +2010-09-08 Rafael Espindola + + * script-sections.cc (Script_sections::add_memory_region): Convert + field precision to int. + * script.cc (script_set_section_region, script_set_section_region): + Convert field precision to int. + +2010-09-08 Rafael Espindola + + * arm.cc (do_finalize_sections): Create the __exidx_start and + __exdix_end symbols even when the section is missing. + +2010-09-08 Nick Clifton + + * README: Remove claim that MEMORY is not supported. + * expression.cc (script_exp_function_origin) + (script_exp_function_length): Move from here to ... + * script.cc: ... here. + (script_set_section_region, script_add_memory) + (script_parse_memory_attr, script_include_directive): New + functions. + * script-sections.cc + (class Memory_region): New class. + (class Output_section_definition): Add set_memory_region, + set_section_vma, set_section_lma and get_section_name methods. + (class Script_Sections): Add add_memory_region, + find_memory_region, find_memory_region_origin, + find_memory_region_length and set_memory_region methods. + Have set_section_addresses method walk the list of set memory + regions. + Extend the print methos to display memory regions. + * script-sections.h: Add prototypes for new methods. + Add enum for MEMORY region attributes. + * yyscript.y: Add support for parsing MEMORY regions. + * script-c.h: Add prototypes for new functions. + * testsuite/Makefile.am: Add test of MEMORY region functionality. + * testsuite/Makefile.in: Regenerate. + * testsuite/memory_test.sh: New script. + * testsuite/memory_test.s: New assembler source file. + * testsuite/memory_test.t: New linker script. + +2010-08-27 Doug Kwan + + * gold/resolve.cc (Symbol_table::should_override): Let a weak + reference override an existing dynamic weak reference. + * testsuite/Makefile.am: Add new test dyn_weak_ref. + * testsuite/Makefile.in: Regenerate. + * testsuite/dyn_weak_ref.sh: New file. + * testsuite/dyn_weak_ref_1.c: Ditto. + * testsuite/dyn_weak_ref_2.c: Ditto. + +2010-08-27 Ian Lance Taylor + + * incremental.h (class Incremental_input_entry): Add virtual + destructor. + +2010-08-27 Ian Lance Taylor + + * testsuite/start_lib_test_3.c: Mark t3 as used. + +2010-08-27 Nick Clifton + + * options.cc (version_script): Fix small typo in previous + whitespace tidyup. + +2010-08-25 Nick Clifton + + * archive.cc: Formatting fixes: Remove whitespace between + typename and following asterisk. Remove whitespace between + function name and opening parenthesis. + * archive.h: Likewise. + * arm.cc: Likewise. + * attributes.cc: Likewise. + * attributes.h: Likewise. + * common.cc: Likewise. + * copy-relocs.cc: Likewise. + * dirsearch.h: Likewise. + * dynobj.cc: Likewise. + * ehframe.cc: Likewise. + * ehframe.h: Likewise. + * expression.cc: Likewise. + * fileread.cc: Likewise. + * fileread.h: Likewise. + * gc.h: Likewise. + * gold-threads.cc: Likewise. + * gold.cc: Likewise. + * i386.cc: Likewise. + * icf.h: Likewise. + * incremental-dump.cc: Likewise. + * incremental.cc: Likewise. + * layout.cc: Likewise. + * layout.h: Likewise. + * main.cc: Likewise. + * merge.cc: Likewise. + * merge.h: Likewise. + * object.cc: Likewise. + * object.h: Likewise. + * options.cc: Likewise. + * options.h: Likewise. + * output.cc: Likewise. + * output.h: Likewise. + * plugin.cc: Likewise. + * plugin.h: Likewise. + * powerpc.cc: Likewise. + * reloc.cc: Likewise. + * script-c.h: Likewise. + * script-sections.cc: Likewise. + * script.cc: Likewise. + * stringpool.cc: Likewise. + * symtab.cc: Likewise. + * symtab.h: Likewise. + * target.cc: Likewise. + * timer.cc: Likewise. + * timer.h: Likewise. + * version.cc: Likewise. + * x86_64.cc: Likewise. + +2010-08-24 Nick Clifton + + PR 11899 + * layout.cc (segment_precedes): Sort segments by their physical + addresses, if they have been set. + +2010-08-23 Cary Coutant + + * archive.cc (Lib_group::add_symbols): Lock object before deleting its + symbols data. + (Lib_group::include_member): Unlock object after deleting its + symbols data. + * testsuite/start_lib_test_3.c: Remove all global symbols to trigger + the bug fixed here. + +2010-08-19 Neil Vachharajani + Cary Coutant + + * gold/archive.h (Add_lib_group_symbols): Add readsyms_blocker_, adjust + constructor, and set_blocker. + * gold/archive.cc (Add_lib_group_symbols::is_runnable): Also check + readsyms_blocker_. + * gold/readsyms.cc (Read_symbols::do_lib_group): Also pass + this->this_blocker_ to Add_lib_group_symbols::set_blocker. + * testsuite/Makefile.am (start_lib_test): New test case. + * testsuite/Makefile.in: Regenerate. + * testsuite/start_lib_test_main.c: New file. + * testsuite/start_lib_test_1.c: New file. + * testsuite/start_lib_test_2.c: New file. + * testsuite/start_lib_test_3.c: New file. + +2010-08-19 Ian Lance Taylor + + * Makefile.in: Rebuild with automake 1.11.1. + * aclocal.m4: Likewise. + * testsuite/Makefile.in: Likewise. + +2010-08-19 Ian Lance Taylor + + PR 10893 + * i386.cc (class Output_data_plt_i386): Update declarations. + Define Global_ifunc and Local_ifunc types. Add global_ifuncs_ and + local_ifuncs_ fields. + (Target_i386::do_plt_section_for_global): New function. + (Target_i386::do_plt_section_for_local): New function. + (Output_data_plt_i386::Output_data_plt_i386): Add symtab + parameter; change all callers. Initialize global_ifuncs_ and + local_ifuncs_. If doing a static link define __rel_iplt_start and + __rel_iplt_end. + (Output_data_plt_i386::add_entry): Handle IFUNC symbols. + (Output_data_plt_i386::add_local_ifunc_entry): New function. + (Output_data_plt_i386::do_write): Fix GOT entries for IFUNC + symbols. + (Target_i386::make_plt_section): New function, broken out of + make_plt_entry. Set sh_info field of .rel.plt to point to .plt. + (Target_i386::make_plt_entry): Call make_plt_section. + (Target_i386::make_local_ifunc_plt_entry): New function. + (Target_i386::Scan::reloc_needs_iplt_for_ifunc): New function. + (Target_i386::Scan::local): Handle IFUNC symbols. Add + R_386_IRELATIVE to switch. + (Target_i386::Scan::global): Likewise. + (Target_i386::Relocate::relocate): Likewise. + (Target_i386::Relocatable_size_for_reloc): Add R_386_IRELATIVE to + switch. + * x86_64.cc (class Output_data_plt_x86_64): Update declarations. + (Target_x86_64::do_plt_section_for_global): New function. + (Target_x86_64::do_plt_section_for_local): New function. + (Output_data_plt_x86_64::Output_data_plt_x86_64): Add symtab + parameter; change all callers. If doing a static link define + __rela_iplt_start and __rela_iplt_end. + (Output_data_plt_x86_64::add_entry): Handle IFUNC symbols. + (Output_data_plt_x86_64::add_local_ifunc_entry): New function. + (Target_x86_64::make_plt_section): Set sh_info field of .rel.plt + to point to .plt. + (Target_x86_64::make_local_ifunc_plt_entry): New function. + (Target_x86_64::Scan::check_non_pic): Add R_X86_64_IRELATIVE to + switch. + (Target_x86_64::Scan::reloc_needs_iplt_for_ifunc): New function. + (Target_x86_64::Scan::local): Handle IFUNC symbols. Add + R_X86_64_IRELATIVE to switch. + (Target_x86_64::Scan::global): Likewise. + (Target_x86_64::Relocate::relocate): Likewise. + (Target_x86_64::Relocatable_size_for_reloc): Add R_X86_64_IRELATIVE to + switch. + * target.h (class Target): Add plt_section_for_global and + plt_section_for_local functions. Add do_plt_section_for_global + and do_plt_section_for_local virtual functions. + * symtab.h (Symbol::needs_plt_entry): Handle IFUNC symbol. Add + clarifying comments. + (Symbol::use_plt_offset): Handle IFUNC symbol. + * object.cc (Sized_relobj::Sized_relobj): Initialize + local_plt_offsets_. + (Sized_relobj::local_has_plt_offset): New function. + (Sized_relobj::local_plt_offset): New function. + (Sized_relobj::set_local_plt_offset): New function. + (Sized_relobj::do_count): Handle IFUNC symbol. + * object.h (class Symbol_value): Add is_ifunc_symbol_ field. Take + a bit away from input_shndx_ field. Add set_is_func_symbol and + is_ifunc_symbol functions. + (class Sized_relobj): Update declarations. Remove Tls_got_entry + and Local_tls_got_offsets. Define Local_plt_offsets. Add + local_plt_offsets_ field. + (Sized_relobj::clear_local_symbols): Clear local_plt_offsets_. + * output.h (class Output_section_data): Add non-const + output_section function. + (class Output_data_got): Update declarations. + (class Output_data_got::Got_entry): Add use_plt_offset_ field. + Add use_plt_offset parameter to global and local constructors. + Change all callers. Change local_sym_index_ field to 31 bits. + Change GSYM_CODE and CONSTANT_CODE accordingly. + * output.cc (Output_data_reloc_base::do_adjust_output_section): If + doing a static link don't set sh_link field. + (Output_data_got::Got_entry::write): Use PLT offset if + appropriate. + (Output_data_got::add_global_plt): New function. + (Output_data_got::add_local_plt): New function. + * target-reloc.h (relocate_section): Handle IFUNC symbol. + * defstd.cc (in_section): Remove entries for __rel_iplt_start, + __rel_iplt_end, __rela_iplt_start, and __rela_iplt_end. + * configure.ac: Set IFUNC automake conditional for glibc >= 2.11. + * testsuite/Makefile.am: Add a bunch of IFUNC tests, all within + IFUNC conditional. + * testsuite/ifunc-sel.h: New file. + * testsuite/ifuncmain1.c: New file. + * testsuite/ifuncmain1vis.c: New file. + * testsuite/ifuncmod1.c: New file. + * testsuite/ifuncdep2.c: New file. + * testsuite/ifuncmain2.c: New file. + * testsuite/ifuncmain3.c: New file. + * testsuite/ifuncmod3.c: New file. + * testsuite/ifuncmain4.c: New file. + * testsuite/ifuncmain5.c: New file. + * testsuite/ifuncmod5.c: New file. + * testsuite/ifuncmain6pie.c: New file. + * testsuite/ifuncmod6.c: New file. + * testsuite/ifuncmain7.c: New file. + * configure, testsuite/Makefile.in: Rebuild. + +2010-08-18 Ian Lance Taylor + + * incremental.cc + (Output_section_incremental_inputs::write_input_files): Add cast + to avoid signed/unsigned comparison warning. + (Output_section_incremental_inputs::write_info_blocks): Likewise. + +2010-08-12 Cary Coutant + + * common.cc (Sort_commons::operator()): Remove unnecessary code. + +2010-08-13 Ian Lance Taylor + + * testsuite/incremental_test_1.c: Add prototype to avoid warning. + +2010-08-12 Cary Coutant + Doug Kwan + + * resolve.cc (Symbol_table::should_override): When a weak dynamic + defintion overrides non-weak undef, remember that the original undef + is not weak. + * symtab.cc (Symbol_table::sized_write_global): For undef without + an original weak binding, set binding to global in output. + * testsuite/Makefile.am: Add new test strong_ref_weak_def. + * testsuite/Makefile.in: Regenerate. + * testsuite/strong_ref_weak_def.sh: New file. + * testsuite/strong_ref_weak_def_1.c: Ditto. + * testsuite/strong_ref_weak_def_2.c: Ditto. + +2010-08-12 Cary Coutant + + * testsuite/incremental_test.sh: Rewrite. + * testsuite/incremental_test_1.c: Rewrite. + * testsuite/incremental_test_2.c: Rewrite. + +2010-08-12 Cary Coutant + + * arm.cc (Target_arm::got_size): Add const. + (Target_arm::got_entry_count): New function. + (Target_arm::plt_entry_count): New function. + (Target_arm::first_plt_entry_offset): New function. + (Target_arm::plt_entry_size): New function. + (Output_data_plt_arm::entry_count): New function. + (Output_data_plt_arm::first_plt_entry_offset): New function. + (Output_data_plt_arm::get_plt_entry_size): New function. + * i386.cc (Target_i386::got_size): Add const. + (Target_i386::got_entry_count): New function. + (Target_i386::plt_entry_count): New function. + (Target_i386::first_plt_entry_offset): New function. + (Target_i386::plt_entry_size): New function. + (Output_data_plt_i386::entry_count): New function. + (Output_data_plt_i386::first_plt_entry_offset): New function. + (Output_data_plt_i386::get_plt_entry_size): New function. + * incremental-dump.cc (dump_incremental_inputs): Adjust call to + find_incremental_inputs_sections. Dump incremental_got_plt section. + * incremental.cc: Include target.h. + (Sized_incremental_binary::do_find_incremental_inputs_sections): Add + parameter. Adjust all callers. Find incremental_got_plt section. + (Incremental_inputs::create_data_sections): Create incremental_got_plt + section. + (Output_section_incremental_inputs::set_final_data_size): Calculate + size of incremental_got_plt section. + (Output_section_incremental_inputs::do_write): Write the + incremental_got_plt section. + (Got_plt_view_info): New struct. + (Local_got_offset_visitor): New class. + (Global_got_offset_visitor): New class. + (Global_symbol_visitor_got_plt): New class. + (Output_section_incremental_inputs::write_got_plt): New function. + * incremental.h (Incremental_binary::find_incremental_inputs_sections): + Add parameter. Adjust all callers. + (Incremental_binary::do_find_incremental_inputs_sections): Likewise. + (Incremental_inputs::got_plt_section): New function. + (Incremental_inputs::got_plt_section_): New data member. + (Incremental_got_plt_reader): New class. + * layout.cc (Layout::create_incremental_info_sections): Add the + incremental_got_plt section. + * object.h (Got_offset_list::get_list): New function. + (Got offset_list::for_all_got_offsets): New function. + (Sized_relobj::local_got_offset_list): New function. + * powerpc.cc (Target_powerpc::got_size): Add const. + (Target_powerpc::got_entry_count): New function. + (Target_powerpc::plt_entry_count): New function. + (Target_powerpc::first_plt_entry_offset): New function. + (Target_powerpc::plt_entry_size): New function. + (Output_data_plt_powerpc::entry_count): New function. + (Output_data_plt_powerpc::first_plt_entry_offset): New function. + (Output_data_plt_powerpc::get_plt_entry_size): New function. + * sparc.cc (Target_sparc::got_size): Add const. + (Target_sparc::got_entry_count): New function. + (Target_sparc::plt_entry_count): New function. + (Target_sparc::first_plt_entry_offset): New function. + (Target_sparc::plt_entry_size): New function. + (Output_data_plt_sparc::entry_count): New function. + (Output_data_plt_sparc::first_plt_entry_offset): New function. + (Output_data_plt_sparc::get_plt_entry_size): New function. + * symtab.h (Symbol::got_offset_list): New function. + (Symbol_table::for_all_symbols): New function. + * target.h (Sized_target::got_entry_count): New function. + (Sized_target::plt_entry_count): New function. + (Sized_target::plt_entry_size): New function. + * x86_64.cc (Target_x86_64::got_size): Add const. + (Target_x86_64::got_entry_count): New function. + (Target_x86_64::plt_entry_count): New function. + (Target_x86_64::first_plt_entry_offset): New function. + (Target_x86_64::plt_entry_size): New function. + (Output_data_plt_x86_64::entry_count): New function. + (Output_data_plt_x86_64::first_plt_entry_offset): New function. + (Output_data_plt_x86_64::get_plt_entry_size): New function. + +2010-08-12 Cary Coutant + + * archive.cc: Include incremental.h. + (Archive::Archive): Initialize incremental_info_. + (Archive::include_member): Record archive members in incremental info. + (Add_archive_symbols::run): Record begin and end of an archive in + incremental info. + (Lib_group::include_member): Record objects in incremental info. + * archive.h (Incremental_archive_entry): Forward declaration. + (Archive::set_incremental_info): New member function. + (Archive::incremental_info): New member function. + (Archive::Unused_symbol_iterator): New class. + (Archive::unused_symbols_begin): New member function. + (Archive::unused_symbols_end): New member function. + (Archive::incremental_info_): New data member. + * incremental-dump.cc (find_input_containing_global): New function. + (dump_incremental_inputs): Dump new incremental info sections. + * incremental.cc: Include symtab.h. + (Output_section_incremental_inputs): New class. + (Sized_incremental_binary::do_find_incremental_inputs_sections): Support + new incremental info sections. + (Sized_incremental_binary::do_check_inputs): Likewise. + (Incremental_inputs::report_archive): Remove. + (Incremental_inputs::report_archive_begin): New function. + (Incremental_inputs::report_archive_end): New function. + (Incremental_inputs::report_object): New function. + (Incremental_inputs::finalize_inputs): Remove. + (Incremental_inputs::report_input_section): New function. + (Incremental_inputs::report_script): Rewrite. + (Incremental_inputs::finalize): Do nothing but finalize string table. + (Incremental_inputs::create_incremental_inputs_section_data): Remove. + (Incremental_inputs::sized_create_inputs_section_data): Remove. + (Incremental_inputs::create_data_sections): New function. + (Incremental_inputs::relocs_entsize): New function. + (Output_section_incremental_inputs::set_final_data_size): New function. + (Output_section_incremental_inputs::do_write): New function. + (Output_section_incremental_inputs::write_header): New function. + (Output_section_incremental_inputs::write_input_files): New function. + (Output_section_incremental_inputs::write_info_blocks): New function. + (Output_section_incremental_inputs::write_symtab): New function. + * incremental.h (Incremental_script_entry): Forward declaration. + (Incremental_object_entry): Forward declaration. + (Incremental_archive_entry): Forward declaration. + (Incremental_inputs): Forward declaration. + (Incremental_inputs_header_data): Remove. + (Incremental_inputs_header): Remove. + (Incremental_inputs_header_write): Remove. + (Incremental_inputs_entry_data): Remove. + (Incremental_inputs_entry): Remove. + (Incremental_inputs_entry_write): Remove. + (enum Incremental_input_type): Add INCREMENTAL_INPUT_ARCHIVE_MEMBER. + (Incremental_binary::find_incremental_inputs_sections): Add parameters. + (Incremental_binary::do_find_incremental_inputs_sections): Likewise. + (Sized_ncremental_binary::do_find_incremental_inputs_sections): + Likewise. + (Incremental_input_entry): New class. + (Incremental_script_entry): New class. + (Incremental_object_entry): New class. + (Incremental_archive_entry): New class. + (Incremental_inputs::Incremental_inputs): Initialize new data members. + (Incremental_inputs::report_inputs): Remove. + (Incremental_inputs::report_archive): Remove. + (Incremental_inputs::report_archive_begin): New function. + (Incremental_inputs::report_archive_end): New function. + (Incremental_inputs::report_object): Change prototype. + (Incremental_inputs::report_input_section): New function. + (Incremental_inputs::report_script): Change prototype. + (Incremental_inputs::get_reloc_count): New function. + (Incremental_inputs::set_reloc_count): New function. + (Incremental_inputs::create_data_sections): New function. + (Incremental_inputs::create_incremental_inputs_section_data): Remove. + (Incremental_inputs::inputs_section): New function. + (Incremental_inputs::symtab_section): New function. + (Incremental_inputs::relocs_section): New function. + (Incremental_inputs::get_stringpool): Add const. + (Incremental_inputs::command_line): Add const. + (Incremental_inputs::inputs): Remove. + (Incremental_inputs::command_line_key): New function. + (Incremental_inputs::input_file_count): New function. + (Incremental_inputs::input_files): New function. + (Incremental_inputs::relocs_entsize): New function. + (Incremental_inputs::sized_create_inputs_section_data): Remove. + (Incremental_inputs::finalize_inputs): Remove. + (Incremental_inputs::Input_info): Remove. + (Incremental_inputs::lock_): Remove. + (Incremental_inputs::inputs_): Change type. + (Incremental_inputs::inputs_map_): Remove. + (Incremental_inputs::current_object_entry_): New data member. + (Incremental_inputs::inputs_section_): New data member. + (Incremental_inputs::symtab_section_): New data member. + (Incremental_inputs::relocs_section_): New data member. + (Incremental_inputs::reloc_count_): New data member. + (Incremental_inputs_reader): New class. + (Incremental_symtab_reader): New class. + (Incremental_relocs_reader): New class. + * layout.cc (Layout::finalize): Move finalization of incremental info + and creation of incremental info sections to follow finalization of + symbol table. Set offsets for postprocessing sections. + (Layout::create_incremental_info_sections): Call + Incremental_inputs::create_data_sections. Add incremental symtab + and relocs sections. Set sh_entsize and sh_link fields. Arrange for + sections to layout after input sections. + * layout.h (struct Timespec): Forward declaration. + (Layout::incremental_inputs): Add const. + (Layout::create_incremental_info_sections): Add parameter. + * main.cc (main): Remove call to Incremental_inputs::report_inputs. + * object.cc: Include incremental.h. + (Relobj::finalize_incremental_relocs): New function. + (Sized_relobj::do_layout): Record input sections in incremental info. + * object.h (Object::output_section): New function. + (Object::output_section_offset): Moved from Relobj. + (Object::get_incremental_reloc_base): New function. + (Object::get_incremental_reloc_count): New function. + (Object::do_output_section): New function. + (Object::do_output_section_offset): Moved from Relobj. + (Object::do_get_incremental_reloc_base): New function. + (Object::do_get_incremental_reloc_count): New function. + (Object::Object): Initialize new data members. + (Relobj::output_section): Renamed do_output_section and moved to + protected. + (Relobj::output_section_offset): Moved to Object. + (Relobj::do_get_incremental_reloc_base): New function. + (Relobj::do_get_incremental_reloc_count): New function. + (Relobj::allocate_incremental_reloc_counts): New function. + (Relobj::count_incremental_reloc): New function. + (Relobj::finalize_incremental_relocs): New function. + (Relobj::next_incremental_reloc_index): New function. + (Relobj::reloc_counts_): New data member. + (Relobj::reloc_bases_): New data member. + (Sized_relobj::do_relocate_sections): Add parameter. Change caller. + (Sized_relobj::relocate_sections): Add parameter. Change all callers. + (Sized_relobj::incremental_relocs_scan): New function. + (Sized_relobj::incremental_relocs_scan_reltype): New function. + (Sized_relobj::incremental_relocs_write): New function. + (Sized_relobj::incremental_relocs_write_reltype): New function. + * plugin.cc (Plugin_manager::add_input_file): Rewrite test for + incremental link. + * readsyms.cc (Read_symbols::do_read_symbols): Move reporting of + archives and object files elsewhere. + (Add_symbols::run): Report object files here. + (Finish_group::run): Report end of archive at end of group. + * reloc.cc: Include layout.h, incremental.h. + (Sized_relobj::do_read_relocs): Need relocations for incremental link. + (Sized_relobj::do_scan_relocs): Record relocations for incremental link. + (Sized_relobj::incremental_relocs_scan): New function. + (Sized_relobj::incremental_relocs_scan_reltype): New function. + (Sized_relobj::do_relocate_sections): Write incremental relocations. + (Sized_relobj::incremental_relocs_write): New function. + (Sized_relobj::incremental_relocs_write_reltype): New function. + * script.cc (read_input_script): Rewrite test for incremental link. + Change call to Incremental_inputs::report_script. + * symtab.h (Symbol_table::first_global_index): New function. + (Symbol_table::output_count): New function. + +2010-08-12 Doug Kwan + + * arm.cc (Target_arm::merge_object_attributes): Check command line + options --no-wchar-size-warning and --no-enum-size-warning. + * options.h (General_options): Add ld-compatible options + --no-enum-size-warning and --no-wchar-size-warning. + +2010-08-04 Ian Lance Taylor + + * x86_64.cc (Target_x86_64::Scan::local): Use + R_X86_64_GNU_VTINHERIT instead of R_386_GNU_VTINHERIT and + R_X86_64_GNU_VTENTRY instead of R_386_GNU_VTENTRY. + (Target_x86_64::Scan::global): Likewise. + (Target_x86_64::Relocate::relocate): Likewise. + (Target_x86_64::Relocatable_size_for_reloc::get_size_for_reloc): + Likewise. + +2010-08-03 Cary Coutant + + * merge.cc (Output_merge_string::do_add_input_section): Count strings + to reserve space in merged_strings vector. Keep total input size + for stats. + (Output_merge_string::do_print_merge_stats): Print total input size. + * merge.h (Output_merge_string): Add input_size_ field. + * stringpool.cc (Stringpool_template::string_length): Move + implementations out of Stringpool_template class and place in + stringpool.h. + * stringpool.h (string_length): Move out of Stringpool_template. + +2010-08-03 Ian Lance Taylor + + PR 11712 + * layout.cc (relaxation_loop_body): If address of load segment is + set, adjust address to include headers if possible. + +2010-08-03 Ian Lance Taylor + + * version.cc (version_string): Bump to 1.10. + +2010-08-03 Ian Lance Taylor + + PR 11805 + * layout.h (enum Output_section_order): Define. + (class Layout): Update declarations. + * layout.cc (Layout::get_output_section): Add order parameter. + Remove is_interp, is_dynamic_linker_section, is_last_relro, and + is_first_non_relro parameters. Change all callers. + (Layout::choose_output_section): Likewise. + (Layout::add_output_section_data): Likewise. + (Layout::make_output_section): Likewise. Set order. + (Layout::default_section_order): New function. + (Layout::layout_eh_frame): Call add_output_section_to_nonload. + * output.cc (Output_section::Output_section): Initialize order_. + Don't initialize deleted fields. + (Output_segment::Output_segment): Don't initialize deleted + fields. + (Output_segment::add_output_section_to_load): New function + replacing add_output_section. Change all callers to call this or + add_output_section_to_nonload. + (Output_segment::add_output_section_to_nonload): New function. + (Output_segment::remove_output_section): Rewrite. + (Output_segment::add_initial_output_data): Likewise. + (Output_segment::has_any_data_sections): Likewise. + (Output_segment::is_first_section_relro): Likewise. + (Output_segment::maximum_alignment): Likewise. + (Output_segment::has_dynamic_reloc): New function replacing + dynamic_reloc_count. Change all callers. + (Output_segment::has_dynamic_reloc_list): New function replacing + dynamic_reloc_count_list. Change all callers. + (Output_segment::set_section_addresses): Rewrite. + (Output_segment::set_offset): Rewrite. + (Output_segment::find_first_and_last_list): Remove. + (Output_segment::set_tls_offsets): Rewrite. + (Output_segment::first_section_load_address): Likewise. + (Output_segment::output_section_count): Likewise. + (Output_segment::section_with_lowest_load_address): Likewise. + (Output_segment::write_section_headers): Likewise. + (Output_segment::print_sections_to_map): Likewise. + * output.h (class Output_data): Remove dynamic_reloc_count_ + field. Add has_dynamic_reloc_ field. Make bools into bitfields. + (Output_data::add_dynamic_reloc): Rewrite. + (Output_data::has_dynamic_reloc): New function. + (Output_data::dynamic_reloc_count): Remove. + (class Output_section): Add order_ field. Remvoe is_relro_local_, + is_last_relro_, is_first_non_relro_, is_interp_, + is_dynamic_linker_section_ fields. Add order and set_order + functions. Remove is_relro_local, set_is_relro_local, + is_last_relro, set_is_last_relro, is_first_non_relro, + set_is_first_non_relro functions, is_interp, set_is_interp, + is_dynamic_linker_section, and set_is_dynamic_linker_section + functions. + (class Output_segment): Change Output_data_list from std::list to + std:;vector. Add output_lists_ field. Remove output_data_ and + output_bss_ fields. Update declarations. + +2010-08-02 Ian Lance Taylor + + * arm.cc (Target_arm::gc_process_relocs): Use typename. + * powerpc.cc (Target_powerpc::gc_process_relocs): Likewise. + * sparc.cc (Target_sparc::gc_process_relocs): Likewise. + +2010-08-02 Ian Lance Taylor + + PR 11855 + * script.cc (Script_options::Script_options): Initialize + symbol_definitions_ and symbol_references_. + (Script_options::add_symbol_assignment): Update + symbol_definitions_ and symbol_references_. + (Script_options::add_symbol_reference): New function. + (script_symbol): New function. + * script.h (class Script_options): Add symbol_definitions_ and + symbol_references_ fields. + (Script_options::referenced_const_iterator): New type. + (Script_options::referenced_begin): New function. + (Script_options::referenced_end): New function. + (Script_options::is_referenced): New function. + (Script_options::any_unreferenced): New function. + * script-c.h (script_symbol): Declare. + * yyscript.y (exp): Call script_symbol. + * symtab.cc: Include "script.h". + (Symbol_table::gc_mark_undef_symbols): Add layout parameter. + Change all callers. Check symbols referenced by scripts. + (Symbol_table::add_undefined_symbols_from_command_line): Add + layout parameter. Change all callers. + (Symbol_table::do_add_undefined_symbols_from_command_line): + Likewise. Break out loop body. Check symbols referenced by + scripts. + (Symbol_table::add_undefined_symbol_from_command_line): New + function broken out of + do_add_undefined_symbols_from_command_line. + * symtab.h (class Symbol_table): Update declarations. + * archive.cc: Include "layout.h". + (Archive::should_include_member): Add layout parameter. Change + all callers. Check for symbol mentioned in expression. + * archive.h (class Archive): Update declaration. + * object.cc (Sized_relobj::do_should_include_member): Add layout + parameter. + * object.h (Object::should_include_member): Add layout parameter. + Change all callers. + (Object::do_should_include_member): Add layout parameter. + (class Sized_relobj): Update declaration. + * dynobj.cc (Sized_dynobj::do_should_include_member): Add layout + parameter. + * dynobj.h (class Sized_dynobj): Update declaration. + * plugin.cc (Sized_pluginobj::do_should_include_member): Add + layout parameter. + * plugin.h (class Sized_pluginobj): Update declaration. + +2010-08-02 Ian Lance Taylor + + PR 11866 + * output.cc (Output_segment::set_offset): Search for the first and + last sections rather than assuming that the list is in order. + (Output_segment::find_first_and_last_list): New function. + * output.h (class Output_segment): Update declarations. + * testsuite/Makefile.am (check_PROGRAMS): Add relro_strip_test. + (relro_strip_test_SOURCES): New variable. + (relro_strip_test_DEPENDENCIES): New variable. + (relro_strip_test_LDFLAGS): New variable. + (relro_strip_test_LDADD): New variable. + (relro_strip_test.so): New target. + +2010-08-02 Ian Lance Taylor + + * i386.cc (class Target_i386): Add got_tlsdesc_ field. + (Target_i386::Target_i386):: Initialize got_tlsdesc_. + (Target_i386::got_tlsdesc_section): New function. + (Target_i386::got_section): Create space for GOT entries for + TLSDESC relocations. + (Target_i386::Scan::local): Use TLSDESC GOT for unoptimized + R_386_TLS_GOTDESC. + (Target_i386::Scan::global): Likewise. + (Target_i386::Relocate::relocate_tls): Adjust GOT offset when + using TLSDESC GOT. + * x86_64.cc (class Target_x86_64): Add got_tlsdesc_ field. + (Target_x86_64::Target_x86_64):: Initialize got_tlsdesc_. + (Target_x86_64::got_tlsdesc_section): New function. + (Target_x86_64::got_section): Create space for GOT entries for + TLSDESC relocations. + (Target_x86_64::Scan::local): Use TLSDESC GOT for unoptimized + R_386_TLS_GOTDESC. + (Target_x86_64::Scan::global): Likewise. + (Target_x86_64::Relocate::relocate_tls): Adjust GOT offset when + using TLSDESC GOT. + +2010-08-02 Ian Lance Taylor + + * testsuite/final_layout.sh: Use dc to convert from hex to + decimal. + +2010-07-29 Sriraman Tallam + + * arm.cc (Target_arm::gc_process_relocs): Add template + paramter to the call to gold::gc_process_relocs. + * i386.cc (Target_i386::gc_process_relocs): Add template + paramter to the call to gold::gc_process_relocs. + * x86_64.cc (Target_x86_64::gc_process_relocs): Add template + parameter to the call to gold::gc_process_relocs. + * powerpc.cc (Target_powerpc::gc_process_relocs): Add + template parameter to the call to gold::gc_process_relocs. + * sparc.cc (Target_sparc::gc_process_relocs): Add template + paramter to the call to gold::gc_process_relocs. + * gc.h (get_embedded_addend_size): New function. + (gc_process_relocs): Save the size of the reloc for use by ICF. + * icf.cc (get_section_contents): Get the addend from the text section + for SHT_REL relocation sections. + * icf.h (Icf::Reloc_addend_size_info): New typedef. + (Icf::Reloc_info): Add new member reloc_addend_size_info. + * int_encoding.h (read_from_pointer): New overloaded function. + * testsuite/Makefile.am (icf_sht_rel_addend_test): New test. + * testsuite/icf_sht_rel_addend_test.sh: New file. + * testsuite/icf_sht_rel_addend_test_1.cc: New file. + * testsuite/icf_sht_rel_addend_test_2.cc: New file. + +2010-07-28 Ralf Wildenhues + + * configure.ac (AM_INIT_AUTOMAKE): Use parallel-tests option. + * Makefile.in: Regenerate. + * testsuite/Makefile.in: Regenerate. + +2010-07-27 Jeffrey Yasskin + + * testsuite/debug_msg.sh: Test mixed weak/strong symbol behavior. + * gold/testsuite/debug_msg.cc: Likewise. + * gold/testsuite/odr_violation1.cc + * gold/testsuite/odr_violation2.cc + +2010-07-21 Cary Coutant + + * merge.h (Output_merge_string::Merged_string): Remove object, shndx, + string, and length fields. + (Output_merge_string::Merged_strings_list): New type. + (Output_merge_string::Merged_strings_lists): New typedef. + (Output_merge_string): Replace merged_strings_ with + merged_strings_lists_. + * merge.cc (Output_merge_string::do_add_input_section): Allocate new + Merged_strings_list per input object and section. Don't store pointer + to the string. Don't store length with each merged string entry. + (Output_merge_string::finalize_merged_data): Loop over list of merged + strings lists. Recompute length of each merged string. + +2010-07-15 Cary Coutant + + * plugin.cc (Plugin_finish::run): Don't call cleanup handlers from + here. + +2010-07-14 Ian Lance Taylor + + * descriptors.cc (Descriptors::open): Report correct name in error + message. + +2010-07-13 Doug Kwan + + * arm.cc (Arm_input_section::Arm_input_section): For a + SHT_ARM_EXIDX section, always keeps the input sections. + (Arm_input_section::set_exidx_section_link): New method. + (Arm_exidx_input_section::Arm_exidx_input_section): Initialize + has_errors_ to false. + (Arm_exidx_input_section::has_errors, + Arm_exidx_input_section::set_has_errors): New methods. + (Arm_exidx_input_section::has_errors_): New data member. + (Arm_relobj::get_exidx_shndx_list): New method. + (Arm_output_section::append_text_sections_to_list): Do not skip + 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 + 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 + moved to Arm_relobj::make_exidx_input_section. Add an assertion to + check that there is no deferred EXIDX section if we exit early. + Instead of not making an EXIDX section in case of an error, make one + and set the has_errors flag of it. + (Target_arm::do_finalize_sections): Fix up links of EXIDX sections + 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 + section list. Do not check for SHF_EXECINSTR section flags but + skip any input section with errors. + * output.cc (Output_section::Output_section): Initialize + always_keeps_input_sections_ to false. + (Output_section::add_input_section): Check for + always_keeps_input_sections_. + * output.h (Output_section::always_keeps_input_sections, + Output_section::set_always_keeps_input_sections): New methods. + (Output_section::always_keeps_input_sections): New data member. + +2010-07-13 Rafael Espindola + + * fileread.cc (try_extra_search_path, find_file): Move to Input_file. + * fileread.h (Input_file): Add try_extra_search_path and find_file. + +2010-07-13 Philip Herron + Ian Lance Taylor + + * output.h (Output_section_lookup_maps::add_merge_section): + Correct check of whether value was inserted. + (Output_section_lookup_maps::add_merge_input_section): Likewise. + (Output_section_lookup_maps::add_relaxed_input_section): + Likewise. + * arm.cc (Target_arm::got_section): Remove used local os. + * i386.cc (Target_i386::got_section): Likewise. + * x86_64.cc (Target_x86_64::got_section): Likewise. + * sparc.cc (Target_sparc::got_section): Likewise. + (Target_sparc::relocate): Remove unused local have_got_offset. + * powerpc.cc (Target_powerpc::relocate): Likewise. + +2010-07-13 Ian Lance Taylor + + * compressed_output.cc (zlib_decompress): Fix signature in + !HAVE_ZLIB_H case. + + * archive.cc (Archive::include_member): Unlock an external member + of a thin archive. Don't bother to delete an object we know is + NULL. + +2010-07-12 Cary Coutant + + * compressed_output.cc (zlib_decompress): New function. + (get_uncompressed_size): New function. + (decompress_input_section): New function. + * compressed_output.h (get_uncompressed_size): New function. + (decompress_input_section): New function. + * dwarf_reader.cc (Sized_dwarf_line_info::Sized_dwarf_line_info) + Handle compressed debug sections. + * layout.cc (is_compressed_debug_section): New function. + (Layout::output_section_name): Map compressed section names to + canonical names. + * layout.h (is_compressed_debug_section): New function. + (is_debug_info_section): Recognize compressed debug sections. + * merge.cc: Include compressed_output.h. + (Output_merge_data::do_add_input_section): Handle compressed + debug sections. + (Output_merge_string::do_add_input_section): Handle compressed + debug sections. + * object.cc: Include compressed_output.h. + (Sized_relobj::Sized_relobj): Initialize new data members. + (build_compressed_section_map): New function. + (Sized_relobj::do_read_symbols): Handle compressed debug sections. + * object.h (Object::section_is_compressed): New method. + (Object::do_section_is_compressed): New method. + (Sized_relobj::Compressed_section_map): New type. + (Sized_relobj::do_section_is_compressed): New method. + (Sized_relobj::compressed_sections_): New data member. + * output.cc (Output_section::add_input_section): Handle compressed + debug sections. + * reloc.cc: Include compressed_output.h. + (Sized_relobj::write_sections): Handle compressed debug sections. + +2010-07-08 Cary Coutant + + * resolve.cc (Symbol_table::resolve): Remember whether undef was + weak when resolving to a dynamic def. + (Symbol_table::should_override): Add adjust_dyndef flag; set it + for weak undef/dynamic def cases. Adjust callers. + * symtab.cc (Symbol::init_fields): Initialize undef_binding_set_ and + undef_binding_weak_. + (Symbol_table::sized_write_globals): Adjust symbol binding. + (Symbol_table::sized_write_symbol): Add binding parameter. + * symtab.h (Symbol::set_undef_binding): New method. + (Symbol::is_undef_binding_weak): New method. + (Symbol::undef_binding_set_, Symbol::undef_binding_weak_): New members. + (Symbol_table::should_override): Add new parameter. + (Symbol_table::sized_write_symbol): Add new parameter. + + * testsuite/weak_undef_file1.cc: Add new test case. + * testsuite/weak_undef_file2.cc: Fix header comment. + * testsuite/weak_undef_test.cc: Add new test case. + +2010-06-29 Doug Kwan + + * arm-reloc-property.cc (Arm_reloc_property::Arm_reloc_property): + Initialize USE_SYMBOL_. + * arm-reloc-property.h (Arm_reloc_property::uses_symbol): New method + definition. + (Arm_reloc_property::uses_symbol_): New data member declaration. + * arm.cc (Target_arm::Relocate::relocate): Exit early if relocation + uses symbol value and symbol is undefined but not weakly undefined. + +2010-06-28 Rafael Espindola + + * plugin.cc (Plugin::load): Use dlerror. + +2010-06-26 Jeffrey Yaskin + + * symtab.cc (detect_odr_violations): When reporting an ODR + violation, report an object where the symbol is defined. + +2010-06-25 Doug Kwan + + * arm.cc (Target_arm::can_check_for_functions_pointers): Return true. + (Target_arm::section_may_have_icf_unsafe_pointers): New method + definition. + (Target_arm::Scan::local_reloc_may_be_function_pointer, + Target_arm::Scan::global_reloc_may_be_function_pointer): Implement + target hook to detect function points. + (Target_arm::Scan::possible_function_pointer_reloc): New method. + * icf.h (Icf::check_section_for_function_pointers): Change type of + parameter SECTION_NAME to const reference to std::string. Use + target hook to determine if section may have unsafe pointers. + * target.h (Target::section_may_have_icf_unsafe_pointers): New + method definition. + +2010-06-21 Rafael Espindola + + * fileread.cc (Input_file::find_fie): New + (Input_file::open): Use Input_file::find_fie. + * fileread.h (Input_file::find_fie): New + * plugin.cc (set_extra_library_path): New. + (Plugin::load): Add set_extra_library_path to the transfer vector. + (Plugin_manager::set_extra_library_path): New. + (Plugin_manager::add_input_file): Use the extra search path if set. + (set_extra_library_path(): New. + * plugin.h (Plugin_manager): Add set_extra_library_path and + extra_search_path_. + +2010-06-19 Cary Coutant + + * layout.cc (gdb_sections): Add .debug_types. + (lines_only_debug_sections): Likewise. + +2010-06-18 Rafael Espindola + + * plugin.cc (add_input_file,add_input_library) + (Plugin_manager::add_input_file): Make filename arguments const. + * plugin.h (Plugin_manager::add_input_file): Make filename arguments + const. + +2010-06-16 Doug Kwan + + * arm.cc (Target_arm::do_finalize_sections): Do not emit an + .ARM.attributes section if we have not merged any input + attributes sections. + +2010-06-15 Viktor Kutuzov + + * arm.cc: Allow combining objects with no EABI version + information. + +2010-06-15 Rafael Espindola + + * plugin.cc (Plugin_hook::run): Set in_real_elf for the start symbol. + +2010-06-15 Viktor Kutuzov + + * fileread.cc: Only #include if HAVE_READV. + (struct iovec): Correct !HAVE_READV definition. + +2010-06-10 Cary Coutant + + * object.cc (Sized_relobj::do_layout): Defer layout for reloc sections. + (Sized_relobj::do_layout_deferred_sections): Do layout for deferred + reloc sections. + * object.h (Sized_relobj::deferred_layout_relocs_): New data member. + + PR 11683 + * symtab.h (Symbol::is_placeholder): New member function. + * target-reloc.h (relocate_section): Check for placeholder symbols. + + * testsuite/Makefile.am (plugin_test_8): New test. + (plugin_test_9): New test. + * testsuite/Makefile.in: Regenerate. + +2010-06-09 Nick Clifton + + * yyscript.y (input_list_element): Allow strings prefixed with + the '-' character. Treat these as libraries. + * script.cc (script_add_library): New function. Adds a library + specified by "-l" found in an input script. + * script-c.h: Add prototype for script_add_library. + +2010-06-07 Doug Kwan + + * arm.cc (Target_arm::do_relax): Reserve more space for stubs. + Restrict stub-group size to be within long conditional branch + range when working around cortex-A8 erratum. + +2010-06-07 Damien Diederen + + * gold-threads.cc (Lock_impl_threads::Lock_impl_threads): Correct + #ifdef typo. + +2010-06-03 Sriraman Tallam + + PR gold/11658 + * output.cc + (Output_section::Input_section_sort_entry::compare_section_ordering): + Change to return non-zero correctly. + (Output_section::Input_section_sort_section_order_index_compare + ::operator()): Change to fix ambiguity in comparisons. + +2010-06-01 Sriraman Tallam + + * gold.h (is_wildcard_string): New function. + * layout.cc (Layout::layout): Pass this pointer to add_input_section. + (Layout::layout_eh_frame): Ditto. + (Layout::find_section_order_index): New method. + (Layout::read_layout_from_file): New method. + * layout.h (Layout::find_section_order_index): New method. + (Layout::read_layout_from_file): New method. + (Layout::input_section_position_): New private member. + (Layout::input_section_glob_): New private member. + * main.cc (main): Call read_layout_from_file here. + * options.h (--section-ordering-file): New option. + * output.cc (Output_section::input_section_order_specified_): New + member. + (Output_section::Output_section): Initialize new member. + (Output_section::add_input_section): Add new parameter. + Keep input sections when --section-ordering-file is used. + (Output_section::set_final_data_size): Sort input sections when + section ordering file is specified. + (Output_section::Input_section_sort_entry): Add new parameter. + Check sorting type. + (Output_section::Input_section_sort_entry::compare_section_ordering): + New method. + (Output_section::Input_section_sort_compare::operator()): Change to + consider section_order_index. + (Output_section::Input_section_sort_init_fini_compare::operator()): + Change to consider section_order_index. + (Output_section::Input_section_sort_section_order_index_compare + ::operator()): New method. + (Output_section::sort_attached_input_sections): Change to sort + according to section order when specified. + (Output_section::add_input_section<32, true>): Add new parameter. + (Output_section::add_input_section<64, true>): Add new parameter. + (Output_section::add_input_section<32, false>): Add new parameter. + (Output_section::add_input_section<64, false>): Add new parameter. + * output.h (Output_section::add_input_section): Add new parameter. + (Output_section::input_section_order_specified): New + method. + (Output_section::set_input_section_order_specified): New method. + (Input_section::Input_section): Initialize section_order_index_. + (Input_section::section_order_index): New method. + (Input_section::set_section_order_index): New method. + (Input_section::section_order_index_): New member. + (Input_section::Input_section_sort_section_order_index_compare): New + struct. + (Output_section::input_section_order_specified_): New member. + * script-sections.cc (is_wildcard_string): Delete and move modified + method to gold.h. + (Output_section_element_input::Output_section_element_input): Modify + call to is_wildcard_string. + (Output_section_element_input::Input_section_pattern + ::Input_section_pattern): Ditto. + (Output_section_element_input::Output_section_element_input): Ditto. + * testsuite/Makefile.am (final_layout): New test case. + * testsuite/Makefile.in: Regenerate. + * testsuite/final_layout.cc: New file. + * testsuite/final_layout.sh: New file. + +2010-06-01 Rafael Espindola + + * plugin.cc (Plugin::load): Pass the output name to the plugin. + +2010-06-01 Rafael Espindola + + * plugin.cc (Sized_pluginobj::::do_add_symbols): Correctly set the + visibility of symbols. + +2010-05-27 Doug Kwan + + * object.cc (Sized_relobj::do_finalize_local_symbols): Use offset + from start of output section instead of address for a local symbol + in a merged or relaxed section when doing a relocatable link. + +2010-05-26 Rafael Espindola + + PR 11604 + * gold/object.cc(Sized_relobj::do_layout_deferred_sections): Avoid + adding sections the garbage collector removed. + * gold/testsuite/Makefile.am: Add test. + * gold/testsuite/Makefile.in: Regenerate. + * gold/testsuite/plugin_test_7.sh: New. + * gold/testsuite/plugin_test_7_1.c: New. + * gold/testsuite/plugin_test_7_2.c: New. + +2010-05-26 Rafael Espindola + + * script-sections.cc (Output_section_definition::set_section_addresses): + Check for --section-start. + +2010-05-26 Doug Kwan + + * arm.cc (Arm_scan_relocatable_relocs): New class. + (Target_arm::relocate_special_relocatable): New method. + (Arm_relocate_functions::arm_branch_common): Handle relocatable link. + (Arm_relocate_functions::thumb_branch_common): Same. + (Target_arm::scan_relocatable_relocs): Use Arm_scan_relocatable_relocs + instead of Default_scan_relocatable_relocs. + * target-reloc.h (relocate_for_relocatable): Let target handle + relocation strategy Relocatable_relocs::RELOC_SPECIAL. + * target.h (Sized_target::relocate_special_relocatable): New method. + +2010-05-25 Viktor Kutuzov + + * timer.cc: Only #include if HAVE_TIMES is defined. + +2010-05-23 Doug Kwan + + * arm.cc (Arm_input_section::do_output_offset): Use convert_types + instead of a cast. + (Target_arm::apply_cortex_a8_workaround): Rewrite a conditional branch + with a direct branch, not a conditional branch, to a stub. + * merge.cc (Output_merge_base::record_input_section): New method + defintion. + (Output_merge_data::do_add_input_section): Record input section if + keeps-input-sections flag is set. + (Output_merge_string::do_add_input_section): Ditto. + * merge.h (Output_merge_base::Output_merge_base): Initialize new data + members KEEPS_INPUT_SECTIONS_, FIRST_RELOBJ_, FIRST_SHNDX_ and + INPUT_SECTIONS_. + (Output_merge_base::keeps_input_sections, + Output_merge_base::set_keeps_input_sections, + Output_merge_base::first_relobj, Output_merge_base::first_shndx): New + method definitions. + (Output_merge_base::Input_sections): New type declaration. + (Output_merge_base::input_sections_begin, + Output_merge_base::input_sections_end, + Output_merge_base::do_set_keeps_input_sections): New method definitions. + (Output_merge_base::bool keeps_input_sections_, + Output_merge_base::first_relobj_, Output_merge_base::first_shndx_, + Output_merge_base::input_sections_): New data members. + (Output_merge_data::do_set_keeps_input_sections): New method + defintion. + (Output_merge_string::do_set_keeps_input_sections): Ditto. + * output.cc (Output_section::Input_section::relobj): Move method + defintion from class declaration to here and handle merge sections. + (Output_section::Input_section::shndx): Ditto. + (Output_section::Output_section): Remove initializations of removed + data members and initialize new data member LOOKUP_MAPS_. + (Output_section::add_input_section): Set keeps-input-sections flag + for a newly created merge output section as appropriate. Adjust code + 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 + 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::build_lookup_maps): New method defintion. + (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. + (Output_section:::add_script_input_section): Adjust code to use + Output_section_lookup_maps class. Update lookup maps for merge + sections also. + (Output_section::discard_states): Use Output_section_lookup_maps. + (Output_section::restore_states): Same. + * output.h (Merge_section_properties): Move class defintion out of + Output_section. + (Output_section_lookup_maps): New class. + (Output_section::Input_section::is_merge_section): New method + defintion. + (Output_section::Input_section::relobj): Move defintion out of class + defintion. Declare method only. + (Output_section::Input_section::shndx): Ditto. + (Output_section::Input_section::output_merge_base): New method defintion. + (Output_section::Input_section::u2_.pomb): New union field. + (Output_section::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 + KEEPS_INPUT_SECTIONS. + (Output_section::build_lookup_maps): New method declaration. + (Output_section::merge_section_map_, + Output_section::merge_section_by_properties_map_, + Output_section::relaxed_input_section_map_, + Output_section::is_relaxed_input_section_map_valid_): Remove data + members. + (Output_section::lookup_maps_): New data member. + +2010-05-21 Doug Kwan + + PR gold/11619 + * arm.cc (Arm_input_section::do_output_offset): Add a cast to + avoid a compilation error. + +2010-05-19 Rafael Espindola + + * script-sections.cc (Output_section_definition::allocate_to_segment): + Update the phdrs_list even when the output section is NULL. + * testsuite/Makefile.am: Add test. + * testsuite/Makefile.in: Regenerate. + * testsuite/script_test_9.cc: New. + * testsuite/script_test_9.sh: New. + * testsuite/script_test_9.t: New. + +2010-05-19 Doug Kwan + + * arm.cc (Arm_input_section::original_size): New method. + (Arm_input_section::do_addralign): Add a cast. + (Arm_input_section::do_output_offset): Remove static cast. + (Arm_input_section::original_addralign, + Arm_input_section::original_size_): Change type to uint32_t. + (Arm_input_section::init): Add safe casts for section alignment + and size. + (Arm_input_section::set_final_data_size): Do not set address and + offset of stub table. + (Arm_output_section::fix_exidx_coverage): Change use of of + Output_section::Simple_input_section to that of + Output_section::Input_section. + (Target_arm::do_relax): Set addresses and file offsets of Stub_tables + except for the first pass. + * output.cc (Output_section::get_input_sections): Change type of + input_sections to std::list. + (Output_section::add_script_input_section): Rename from + Output_section::add_simple_input_section. Change type of SIS + parameter from Simple_input_section to Input_section. + * output.h (Output_section::Simple_input_section): Remove class. + (Output_section::Input_section): Change class visibility to public. + (Output_section::Input_section::addralign): Use stored alignments + for special input sections if set. + (Output_section::Input_section::set_addralign): New method. + (Output_section::get_input_sections): Change parameter type from + list of Simple_input_section to list of Input_section. + (Output_section::add_script_input_section): Rename from + Output_section::add_simple_input_section. Change first parameter's + type from Simple_input_section to Input_section and remove the + second and third parameters. + * script-sections.cc (Input_section::Input_section_list): Change + type to list of Output_section::Input_section/ + (Input_section_info::Input_section_info): Change parameter type of + INPUT_SECTION to Output_section::Input_section. + (Input_section_info::input_section): Change return type. + (Input_section_info::input_section_): Change type to + Output_section::Input_section. + (Output_section_element_input::set_section_addresses): Adjust code + to use Output_section::Input_section instead of + Output_section::Simple_input_section. Adjust code for renaming + of Output_section::add_simple_input_section. + (Orphan_output_section::set_section_addresses): Ditto. + +2010-05-18 Ralf Wildenhues + + * gold.h (Unordered_multimap, Unordered_map): Fix defines for + when neither HAVE_TR1_UNORDERED_MAP nor HAVE_EXT_HASH_MAP are set. + +2010-05-18 Rafael Espindola + + * options.cc (General_options::finalize): Handle -nostdlib. + * options.h (nostdlib): New option. + * script.cc (script_add_search_dir): Handle -nostdlib. + +2010-05-12 Doug Kwan + + * arm.cc (Target_arm::do_finalize_sections): Create an empty + attributes section only if there no attributes section after merging. + (Target_arm::merge_object_attributes): Move value of + Tag_MPextension_use_legacy to that of Tag_MPextension_use. + Handle Tag_DIV_use and Tag_MPextension_use_legacy. + * testsuite/Makefile.am (check_SCRIPTS): Add arm_attr_merge.sh + (check_DATA): Add arm_attr_merge_6.stdout, arm_attr_merge_6r_stdout + and arm_attr_merge_7.stdout. + (arm_attr_merge_6.stdout, arm_attr_merge_6 arm_attr_merge_6a.o + arm_attr_merge_6b.o, arm_attr_merge_6r.stdout, arm_attr_merge_6r, + arm_attr_merge_7.stdout, arm_attr_merge_7, arm_attr_merge_7a.o, + arm_attr_merge_7b.o): New rules. + (MOSTLYCLEANFILES): Add arm_attr_merge_6, arm_attr_merge_6r and + arm_attr_merge_7 + * testsuite/Makefile.in: Regenerate. + * testsuite/arm_attr_merge.sh: New file. + * testsuite/arm_attr_merge_[67][ab].s: Same. + +2010-05-05 Nick Clifton + + * po/es.po: Updated Spanish translation. + +2010-04-27 H.J. Lu + + * Makefile.am (install-exec-local): Properly install gold as + default cross linker. + * Makefile.in: Regenerated. + +2010-04-27 H.J. Lu + Nick Clifton + + * configure.ac (install_as_default): Define and set to false + unless --enable-gold or --enable-gold=both/gold has been + specified. + * configure: Regenerate. + + * Makefile.am (install-exec-local): Install the executable as + 'ld.gold'. If install_as_default is true then also install it as + 'ld'. + * Makefile.in: Regenerated. + +2010-04-24 Ian Lance Taylor + + * layout.cc (Layout::layout_reloc): In relocatable link don't + combine reloc sections for grouped sections. + +2010-04-23 Sriraman Tallam + + * gc.h (gc_process_relocs): Pass information on relocs pointing to + sections that are not ordinary to icf. + * icf.cc (get_section_contents): Handle relocation pointing to section + with no object or shndx information. + * testsuite/Makefile.am: Remove icf_virtual_function_folding_test.sh + * testsuite/Makefile.in: Regenerate. + * testsuite/icf_virtual_function_folding_test.cc: Remove printf. + * testsuite/icf_virtual_function_folding_test.sh: Delete file. + +2010-04-22 Ian Lance Taylor + + * expression.cc (Expression::Expression_eval_info): Add + result_alignment_pointer field. + (Expression::eval_with_dot): Add result_alignment_pointer + parameter. Change all callers. + (Expression::eval_maybe_dot): Likewise. + (class Binary_expression): Add alignment_pointer parameter to + left_value and right_value. Change all callers. + (BINARY_EXPRESSION): Set result alignment. + (class Trinary_expression): Add alignment_pointer parameter to + arg2_value and arg3_value. Change all callers. + (Trinary_cond::value): Set result alignment. + (Max_expression::value, Min_expression::value): Likewise. + (Align_expression::value): Likewise. + * script-sections.cc (class Sections_element): Add dot_alignment + parameter to set_section_addresses virtual function. Update + instantiations. + (class Output_section_element): Likewise. + (Script_sections::create_segments): Add dot_alignment parameter. + Change all callers. + (Script_sections::create_segments_from_phdrs_clause): Likewise. + (Script_sections::set_phdrs_clause_addresses): Likewise. + * script-sections.h: Update declarations. + * script.h: Update declarations. + * output.h (Output_segment::set_minimum_p_align): Don't decrease + min_p_align. + * testsuite/script_test_3.t: Set large alignment. + * testsuite/script_test_3.sh: Make sure that at least one LOAD + segment has expected alignment. + +2010-04-22 Nick Clifton + + * po/gold.pot: Updated by the Translation project. + * po/vi.po: Updated Vietnamese translation. + +2010-04-22 H.J. Lu + + * testsuite/Makefile.am (check_PROGRAMS): Add + icf_virtual_function_folding_test. + * testsuite/Makefile.in: Regenerated. + +2010-04-15 Andrew Haley + + * options.h (merge_exidx_entries): New option. + * arm.cc (class Arm_exidx_fixup): Add new arg, merge_exidx_entries. + (class Arm_exidx_fixup::merge_exidx_entries_): New member. + (Output_section::fix_exidx_coverage): Add new arg, merge_exidx_entries. + (Target_arm::merge_exidx_entries): New function. + (process_exidx_entry): Don't merge if merge_exidx_entries_ is false. + (Arm_output_section::fix_exidx_coverage): Pass merge_exidx_entries + to Arm_exidx_fixup constructor. + Add new arg, merge_exidx_entries. + (Target_arm::fix_exidx_coverage): pass merge_exidx_entries to + Arm_output_section::fix_exidx_coverage. + +2010-04-18 Sriraman Tallam + + * icf.cc (get_section_contents): Check for preemptible functions. + Ignore addend when appropriate. + * symtab.cc (should_add_dynsym_entry): Add new parameter. Check for + section folded. + (add_from_relobj): Check for section folded. + (set_dynsym_indexes): Fix call to should_add_dynsym_entry. + * symtab.h (should_add_dynsym_entry): Add new parameter. + * target-reloc.h (scan_relocs): Check for section folded. + * x86_64.cc (Target_x86_64::Scan::possible_function_pointer_reloc): + Check reloc types for function pointers in shared objects. + * testsuite/Makefile.am (icf_virtual_function_folding_test): New test + case. + (icf_preemptible_functions_test): New test case. + (icf_string_merge_test): New test case. + * testsuite.Makefile.in: Regenerate. + * testsuite/icf_safe_so_test.sh: Change to not fold foo_glob and + bar_glob. Refactor code. + * testsuite/icf_preemptible_functions_test.cc: New file. + * testsuite/icf_preemptible_functions_test.sh: New file. + * testsuite/icf_string_merge_test.cc: New file. + * testsuite/icf_string_merge_test.sh: New file. + * testsuite/icf_virtual_function_folding_test.cc: New file. + * testsuite/icf_virtual_function_folding_test.sh: New file. + +2010-04-14 Doug Kwan + + * arm.cc (Arm_output_section::fix_exidx_coverage): Mark object + for local symbol recounting if we remove a section due to ICF. + * gold.cc (queue_middle_gc_tasks): Create a dummy blocker if + there are no regular objects in input. + +2010-04-13 Doug Kwan + + * arm.cc (Arm_input_section::set_final_data_size): Compute + accurate final data size instead of using current data size. + +2010-04-09 Doug Kwan + + * layout.cc (Layout::choose_output_section): Handle script section + types. + (Layout::make_output_section_for_script): Add section type parameter. + Handle script section types. + * layout.h (Layout::make_output_section_for_script): Add section + type parameter. + * output.cc (Output_section::Output_section): Initialize data member + is_noload_. + (Output_section::do_reset_address_and_file_offset): Do not set address + to 0 if section is a NOLOAD section. + * output.h (Output_section::is_noload): New method. + (Output_section::set_is_noload): Ditto. + (Output_section::is_noload_): New data member. + * script-c.h (Script_section_type): New enum type. + (struct Parser_output_section_header): Add new file section_type. + * script-sections.cc (Sections_element::output_section_name): Add + parameter for returning script section type. + (Output_section_definition::output_section_name): Ditto. + (Output_section_definition::section_type)P; New method. + (Output_section_definiton::script_section_type_name): Ditto. + (Output_section_definition::script_section_type_): New data member. + (Output_section_definition::Output_section_definition): Initialize + data member Output_section_definition::script_section_type_. + (Output_section_definition::create_sections): Pass script section type + to Layout::make_output_section_for_script. + (Output_section_definition::output_section_name): Return script + section type to caller. + (Output_section_definition::set_section_address): Do not advance + dot value and load address if section type is NOLOAD. Set address + of NOLOAD sections regardless of section flags. + (Output_section_definition::print): Print section type if it is + not SCRIPT_SECTION_TYPE_NONE. + (Output_section_definition::section_type): New method. + (Output_section_definition::script_section_type_name): Ditto. + (Script_sections::output_section_name): Add new parameter + PSECTION_TYPE for returning script section type. Pass it to + 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 + returning script section type. + * script.cc (script_keyword_parsecodes): Add keywords COPY, DSECT, + INFO and NOLOAD. + * yyscript.y (union): Add new field SECTION_TYPE. + (COPY, DSECT, INFO, NOLOAD): New tokens. + (opt_address_and_section_type): Change type to output_section_header. + (section_type): New non-terminal + (section_header): Handle section type. + (opt_address_and_section_type): Return section type value. + +2010-04-09 H.J. Lu + + * testsuite/plugin_common_test_1.c (foo): Add prototype. + * testsuite/plugin_common_test_2.c (foo): Likewise. + +2010-04-08 Doug Kwan + + * merge.cc (Output_merge_data::set_final_data_size): Handle empty + Output_merge_data. + * output.cc (Output_section::add_merge_input_section): Simplify + code and return status of Output_merge_base::add_input_section. + Update merge section map only if Output_merge_base::add_input_section + returns true. + +2010-04-07 Doug Kwan + + * arm.cc (Arm_relobj::scan_section_for_cortex_a8_erratum): Warn + if section is marked as containing instructions but has no mapping + symbols. + (Arm_relobj::do_count_local_symbols): Call adjust_sym_shndx to get + correct section index. + (Arm_relobj::find_linked_text_section): Ditto. + +2010-04-07 Cary Coutant + + * archive.cc (include_member): Destroy Read_symbols_data object before + releasing file. + * object.cc (Read_symbols_data::~Read_symbols_data) New destructor. + * object.h (Read_symbols_data::Read_symbols_data) New constructor. + (Read_symbols_data::~Read_symbols_data) New destructor. + (Section_relocs::Section_relocs) New constructor. + (Section_relocs::~Section_relocs) New destructor. + (Read_relocs_data::Read_relocs_data) New constructor. + (Read_relocs_data::~Read_relocs_data) New destructor. + * testsuite/binary_unittest.cc (Sized_binary_test): Set sd member + pointers to NULL after deleting. + +2010-04-07 Doug Kwan + + * arm.cc: Replace "endianity" with "endianness" in comments. + (Arm_exidx_cantunwind): Ditto. + (Arm_relobj::Arm_relobj): Initialize merge_flags_and_attribures. + (Arm_relobj::merge_flags_and_attributes): New method. + (Arm_relobj::merge_flags_and_attributes_): New data member. + (Arm_exidx_cantunwind::do_fixed_endian_write): Fix formatting. + (Arm_relobj::scan_sections_for_stubs): Ditto. + (Arm_relobj::do_read_symbols): Check to see if we really want to + merge processor-specific flags and attributes. Exit early if + an object is empty except for section names and the undefined symbol. + (Target_arm::do_finalize_sections): Move check for ELF format to + Arm_relobj::do_read_symbols. Merge processor specific flags and + attributes from a regular object only when we have determined that + it is aapropriate. Do not create an .ARM.attributes section in + output if there is no regular input object. + (Target_arm::merge_processor_specific_flags): Check + --warn-mismatch before printing any error. + (Target_arm::merge_object_attributes): Ditto. + * gold.cc (queue_middle_tasks): Handle the case in which there is + no regular object in input. + * options.cc (General_options::parse_EB): New method. + (General_options::parse_EL): Same. + (General_options::General_options): Initialize endianness_. + * options.h (-EB, -EL, -no-pipeline-knowledge, -p, --warn-mismatch): + New options. + (General_options::Endianness): New enum. + (General_options::endianness): New method. + (General_options::endianness_): New data member. + * parameters.cc (Parameters::set_options): Check target endianness. + (Parameters::set_target_once): Ditto. + (Parameters::check_target_endianness): New method. + (parameters_force_valid_target): If either -EL or -EB is specified, + use it to define endianness of default target. + * parameters.h (Parameters::check_target_endianness): New method + declaration. + * target.h (class Target): Change "endianity" to "endianness" + in comments. + +2010-04-07 Ralf Wildenhues + + * configure.ac (AM_INIT_AUTOMAKE): Add option no-dist. + * configure: Regenerate. + * Makefile.in: Regenerate. + * testsuite/Makefile.in: Regenerate. + +2010-04-06 Cary Coutant + + gcc PR lto/42757 + * plugin.cc (Pluginobj::get_symbol_resolution_info): Check for + prevailing definitions of common symbols. + * testsuite/plugin_test_6.sh: New test case. + * testsuite/plugin_common_test_1.c: New test case. + * testsuite/plugin_common_test_2.c: New test case. + * testsuite/Makefile.am (plugin_test_6): New test case. + * testsuite/Makefile.in: Regenerate. + +2010-04-06 Nick Clifton + + * po/vi.po: New Vietnamese translation. + +2010-03-30 Doug Kwan + + * arm.cc (Target_arm::using_thumb_only): Handle v6-M + +2010-03-25 Doug Kwan + + * gold/arm.cc (Arm_exidx_fixup::update_offset_map): Rearrange code + to avoid a conversion warning on a 32-bit host. + +2010-03-24 Ian Lance Taylor + + * testsuite/script_test_3.t: Add a TLS segment. + * testsuite/Makefile.am (check_PROGRAMS): Add + tls_phdrs_script_test. + (tls_phdrs_script_test_SOURCES): Define. + (tls_phdrs_script_test_DEPENDENCIES): Define. + (tls_phdrs_script_test_LDFLAGS): Define. + (tls_phdrs_script_test_LDADD): Define. + * testsuite/Makefile.in: Rebuild. + +2010-03-23 Cary Coutant + + * fileread.cc (find_or_make_view): Fix comment. + +2010-03-23 Ian Lance Taylor + + * script-sections.cc (class Orphan_section_placement): Define + PLACE_TLS and PLACE_TLS_BSS. + (Orphan_section_placement::Orphan_section_placement): Initialize + new places. + (Orphan_section_placement::find_place): Handle SHF_TLS sections. + * testsuite/Makefile.am (check_PROGRAMS): Add tls_script_test. + (tls_script_test_SOURCES): Define. + (tls_script_test_DEPENDENCIES): Define. + (tls_script_test_LDFLAGS): Define. + (tls_script_test_LDADD): Define. + * testsuite/Makefile.in: Rebuild. + +2010-03-22 Doug Kwan + + * arm.cc (Arm_relocate_functions::abs8, + Arm_relocate_functions::abs16): Use correct check for overflow + specified in the ARM ELF specs. + (Arm_relocate_functions): thumb_branch_common. Handle bit 1 of branch + target of a BLX instruction specially. + (Reloc_stub::stub_type_for_reloc): Ditto. + (Relocate::relocate): Use symbolic names instead of numeric relocation + codes to report error. + (Target_arm::do_relox): Reduce default stub-group size for Cortex-A8 + workaround. + * testsuite/Makefile.am (check_DATA): add thumb_blx_in_range.stdout, + thumb_blx_out_of_range.stdout, thumb2_blx_in_range.stdout and + thumb2_blx_out_of_range.stdout + (thumb_bl_out_of_range, thumb_bl_out_of_range.o, + thumb2_bl_out_of_range, thumb2_bl_out_of_range.o): Fix dependenices. + (thumb_blx_in_range.stdout, thumb_blx_in_range, thumb_blx_in_range.o, + thumb_blx_out_of_range.stdout, thumb_blx_out_of_range, + thumb_blx_out_of_range.o, thumb2_blx_in_range.stdout, + 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, + thumb2_blx_in_range and thumb2_blx_out_of_range. + * testsuite/Makefile.in: Regenerate. + * arm_branch_in_range.sh: Add tests for THUMB BLX. + * testsuite/thumb_blx_in_range.s: New file. + * testsuite/thumb_blx_out_of_range.s: New file. + +2010-03-22 Rafael Espindola + + * archive.cc (Should_include): Move to archive.h. + (should_include_member): Make it a member of Archive. + (Lib_group): New. + (Add_lib_group_symbols): New. + * archive.h: Include options.h. + (Archive_member): Moved from Archive. + (Should_include): Moved from archive.cc. + (Lib_group): New. + (Add_lib_group_symbols): New. + * dynobj.cc (do_should_include_member): New. + * dynobj.h (do_should_include_member): New. + * gold.cc (queue_initial_tasks): Update call to queue. + * main.cc (main): Print lib group stats. + * object.cc (do_should_include_member): New. + * object.h: Include archive.h. + (Object::should_include_member): New. + (Object::do_should_include_member): New. + (Sized_relobj::do_should_include_member): New. + * options.cc (General_options::parse_start_lib): New. + (General_options::parse_end_lib): New. + (Input_arguments::add_file): Handle lib groups. + (Input_arguments::start_group): Check we are not in a lib. + (Input_arguments::start_lib): New. + (Input_arguments::end_lib): New. + * options.h (General_options): Add start_lib and end_lib. + (Input_argument::lib_): New. + (Input_argument::lib): New. + (Input_argument::is_lib): New. + (Input_file_lib): New. + (Input_arguments::in_lib_): New. + (Input_arguments::in_lib): New. + (Input_arguments::start_lib): New. + (Input_arguments::end_lib_): New. + * plugin.cc (Pluginobj::get_symbol_resolution_info): Mark symbols + in unused members as preempted. + (Sized_pluginobj::do_should_include_member): New. + * plugin.h (Sized_pluginobj::do_should_include_member): New. + * readsyms.cc (Read_symbols::locks): If we are just reading a member, + return the blocker. + (Read_symbols::do_whole_lib_group): New. + (Read_symbols::do_lib_group): New. + (Read_symbols::do_read_symbols): Handle lib groups. + (Read_symbols::get_name): Handle lib groups. + * readsyms.h (Read_symbols): Add an archive member pointer. + (Read_symbols::do_whole_lib_group): New. + (Read_symbols::do_lib_group): New. + (Read_symbols::member_): New. + * script.cc (read_input_script): Update call to queue_soon. + +2010-03-19 Doug Kwan + + * arm.cc (Stub_table::Stub_table): Initialize new data members + Stub_table::reloc_stubs_size_ and Stub_table::reloc_stubs_addralign_. + (Stub_table::add_reloc_stub): Assign stub offset and update + 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::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. + * 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::offset_. + * stringpool.h (Stringpool_template::set_no_zero_null): Set + Stringpool_template::offset_ to zero. + +2010-03-15 Doug Kwan + + * stringpool.cc (Stringpool_template::Stringpool_template): Initialize + offset_. + (Stringpool_template::new_key_offset): New method. + (Stringpool_template::add_string): Assign offsets when adding new + strings. + (Stringpool_template::set_string_offsets): Do not set string offsets + 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::size_): New data member. + (Stringpool_template::set_no_zero_null): Assert string set is empty. + (Stringpool_template::new_key_offset): New method declaration. + (Stringpool_template::offset_): New data member. + +2010-03-15 Rafael Espindola + + * readsyms.cc (Read_symbols::do_read_symbols): Update calls to + Add_symbols' constructor. + * readsyms.h (Add_symbols): Remove the input_group member. + +2010-03-10 Ian Lance Taylor + + * reloc.cc (Sized_relobj::split_stack_adjust_reltype): Call the + target to ask whether a reference to a symbol requires a stack + split. + * target.h (Target::is_call_to_non_split): New function. + (Target::do_is_call_to_non_split): Declare virtual function. + * target.cc: Include "symtab.h". + (Target::do_is_call_to_non_split): New function. + * i386.cc (Target_i386::do_is_call_to_non_split): New function. + +2010-03-10 Cary Coutant + + * fileread.cc (File_read::~File_read): Don't delete whole_file_view_. + (File_read::open[1]): Remove initial mapping of whole_file_view_. + (File_read::open[2]): Add whole_file_view_ to list of views. + (File_read::make_view): Remove test of whole_file_view_. + (File_read::find_or_make_view): Create whole_file_view_ if + necessary. + (File_read::clear_views): Replace bool parameter with enum; + adjust all callers. Don't delete views with permanent data; + do delete cached views and views from archives if + --no-keep-files-mapped is set. Set whole_file_view_ to NULL + if clearing the corresponding view. + * fileread.h (File_read::Clear_views_mode): New enum. + (File_read::View::is_permanent_view): New method. + (File_read::clear_views): Replace bool parameter + with enum; adjust all callers. + * options.h (General_options): Change keep_files_mapped option; + add map_whole_files. + * readsyms.cc (Add_symbols::run): Delete sd_ object before + releasing the file. + * reloc.cc (Scan_relocs::run): Delete rd_ object before releasing + the file. + +2010-03-10 David S. Miller + + * sparc.cc (Target_sparc::Scan::local): Accept R_SPARC_WPLT30. + +2010-03-09 Sriraman Tallam + + * icf.cc (get_section_contents): Add '@' marker after processing the + merge reloc. + +2010-03-08 Doug Kwan + + * gold/arm.cc (Arm_exidx_fixup::update_offset_map): Fix build breakage + due to a conversion warning. + (Arm_relobj::update_output_local_symbol_count): Check for local + symbol with unset output index. + +2010-03-05 Ian Lance Taylor + + * options.h (class General_options): Add --spare-dynamic-tags. + * output.cc (Output_data_dynamic::set_final_data_size): Implement + --spare-dynamic-tags. + +2010-03-05 Ian Lance Taylor + + * incremental.cc: Include "libiberty.h". + +2010-03-05 Rainer Orth + + * dynobj.h (Verdef::Verdef): Add is_info arg, is_info member + function, is_info_ member. + * dynobj.cc (Verdef::write): Set VER_FLG_INFO if this->is_info_. + (Versions::Versions): Update caller. + (Versions::define_base_version): Likewise. + (Versions::add_def): Likewise. + +2010-03-03 Sriraman Tallam + + * i386.cc (Target_i386::can_check_for_function_pointers): New function. + (Scan::possible_function_pointer_reloc): New function. + (Scan::local_reloc_may_be_function_pointer): Change to call + possible_function_pointer_reloc. + (Scan::global_reloc_may_be_function_pointer): Ditto. + * icf.h (Icf::check_section_for_function_pointers): Change to reject + relocations in ".data.rel.ro._ZTV" section. + * testsuite/icf_safe_so_test.sh: Change to pass i386. + * testsuite/icf_safe_so_test.cc: Ditto. + * testsuite/icf_safe_test.cc: Ditto. + * testsuite/icf_safe_test.sh: Ditto. + +2010-03-03 Viktor Kutuzov + Ian Lance Taylor + + * target-reloc.h (relocate_section): Check the symbol table index + for -1U before setting the local symbol index. + (scan_relocatable_relocs): If copying the relocation, record that + the local symbol is required. + * object.h (Symbol_value::is_output_symtab_index_set): New + function. + (Symbol_value::may_be_discarded_from_output_symtab): New + function. + (Symbol_value::has_output_symtab_entry): New function. + (Symbol_value::needs_output_symtab_entry): Remove. + (Symbol_value::output_symtab_index): Make sure the symbol index is + set. + (Symbol_value::set_output_symtab_index): Make sure the symbol + index is not set. Make sure the new index is valid. + (Symbol_value::set_must_have_output_symtab_entry): New function. + (Symbol_value::has_output_dynsym_entry): New function. + (Symbol_value::set_output_dynsym_index): Make sure the new index + is valid. + (Sized_relobj::set_must_have_output_symtab_entry): New function. + * object.cc (Sized_relobj::do_count_local_symbols): Only discard a + local symbol if permitted. + (Sized_relobj::do_finalize_local_symbols): Call + is_output_symtab_index_set rather than needs_output_symtab_entry. + (Sized_relobj::write_local_symbols): Call has_output_symtab_entry + rather than needs_output_symtab_entry. Call + has_output_dynsym_entry rather than needs_output_dynsym_entry. + * arm.cc (Arm_relobj::update_output_local_symbol_count): Call + is_output_symtab_index_set rather than needs_output_symtab_entry. + * testsuite/discard_locals_relocatable_test.c: New file. + * testsuite/discard_locals_test.sh: Test -r. + * testsuite/Makefile.am (check_DATA): Add + discard_locals_relocatable_test1.syms, + discard_local_relocatable_test2.syms. + (MOSTLYCLEANFILES): Likewise. Also add + discard_locals_relocatable_test1.lout and + discard_locals_relocatable_test2.out. + (discard_locals_relocatable_test1.syms): New target. + (discard_locals_relocatable_test.o): New target. + (discard_locals_relocatable_test1.out): New target. + (discard_locals_relocatable_test2.syms): New target. + (discard_locals_relocatable_test2.out): New target. + (various): Add missing ../ld-new dependencies. + * testsuite/Makefile.in: Rebuild. + +2010-03-03 Nick Clifton + + * po/fi.po: New Finnish translation. + +2010-03-01 Doug Kwan + + * layout.cc (Layout::Layout): Force section types of .init_array*, + .preinit_array* and .fini_array* sections. + * output.cc (Output_section::Input_section_sort_entry::has_priority): + Fix check of return value of std::string::find.(). + (Output_section::Input_section_sort_compare::operator()): Remove + comment about .init_array. + (Output_section::Input_section_sort_init_fini_compare::operator()): + New method. + (Output_section::sort_attached_input_sections): Handle .init_array + and .fini_array specially. + * output.h (Output_section::Inut_section_sort_compare): Update + comment. + (Output_section::Input_section_sort_init_fini_compare): New struct. + +2010-02-26 Doug Kwan + + * arm.cc (Target_arm::Relocate::reloc_is_non_pic): Treat + R_ARM_PREL31 and R_ARM_SBREL31 as position independent. + * testsuite/debug_msg.sh: Avoid matching source line number for + use of global variable undef_int. + +2010-02-26 Doug Kwan + + * arm.cc (Target_arm::scan_reloc_for_stub): Move code handling + R_ARM_V4BX to Target_arm::scan_reloc_section_for_stubs. + (Target_arm::scan_reloc_section_for_stubs): Instead of calling + scan_reloc_for_stub, do all processing of R_ARM_V4BX here. + * options.cc (General_options::General_options): Initialize member + fix_v4bx_. + * testsuite/Makefile.am (check_SCRIPTS): Add arm_fix_v4bx.sh + (check_DATA): Add arm_fix_v4bx.stdout, arm_fix_v4bx_interworking.stdout + and rm_no_fix_v4bx.stdout + (arm_fix_v4bx.stdout, arm_fix_v4bx, arm_fix_v4bx.o, + arm_fix_v4bx_interworking.stdout, arm_fix_v4bx_interworking, + arm_no_fix_v4bx.stdout, arm_no_fix_v4bx): New make rules. + (MOSTLYCLEANFILES): Add arm_fix_v4bx, arm_fix_v4bx_interworking + and arm_no_fix_v4bx. + * Makefile.in: Regenerate. + * testsuite/arm_fix_v4bx.s: New file. + * testsuite/arm_fix_v4bx.sh: Ditto. + +2010-02-24 Doug Kwan + + * arm.cc (Target_arm::got_section): Make the .got section the first + non RELRO section in the data segment. + * testsuite/script_test_5.sh: Fix match patterns to avoid matching + suffixes of section names. + +2010-02-24 Doug Kwan + + * arm.cc (Target_arm::do_finalize_sections): Skip processor specific + 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::format): New method definition. + (Input_file::format_):: New data member. + +2010-02-24 Doug Kwan + + * arm.cc (Arm_output_data_got): New class. + (ARM_TCB_SIZE): New constant + (Target_arm): Use Arm_output_data_got instead of Output_data_got. + (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 + garbage collection. + (Target_arm::got_mode_index_entry): Handle static linking. + (Target_arm::Scan::local): Ditto. + (Target_arm::Scan::global): Ditto. + (Target_arm::Relocate::relocate_tls): Handle static linking. Fix + all incorrectly implemented relocations. + (Target_arm::fix_exidx_coverage): Pass layout to + Arm_output_section::fix_exidx_coverage. + * layout.cc (Layout::section_name_mapping): Remove trailing dots + from ".ARM.exidx." and ".ARM.extab.". + +2010-02-23 Viktor Kutuzov + + * arm.cc (Target_arm::do_finalize_sections): Create attribute + section if it does not already exist. + * attributes.cc (Attributes_section_data::Attributes_section_data): + Don't crash if size is zero. + +2010-02-23 Viktor Kutuzov + Ian Lance Taylor + + * gold.cc (queue_middle_tasks): If no input files were opened, + exit. + * workqueue.h (Task_function::Task_function): Assert that there is + a blocker. + +2010-02-22 Doug Kwan + + * gold-threads.h (Once::~Once): Explicitly define virtual destructor. + * icf.cc (get_section_contents): Cast snprintf arguments to long long + types to avoid warnings due to different uint64_t implementations + on different hosts. + +2010-02-21 Doug Kwan + + * 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. + * 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, + thumb2_bl_in_range.stdout and thumb2_bl_out_of_range.stdout. + (arm_bl_in_range.stdout, arm_bl_in_range, arm_bl_in_range.o, + arm_bl_out_of_range.stdout, arm_bl_out_of_range, + arm_bl_out_of_range.o, thumb_bl_in_range.stdout, thumb_bl_in_range, + thumb_bl_in_range.o, thumb_bl_out_of_range.stdout, + thumb_bl_out_of_range thumb_bl_out_of_range.o, + thumb2_bl_in_range.stdout, thumb2_bl_in_range, thumb2_bl_in_range.o + thumb2_bl_out_of_range.stdout, thumb2_bl_out_of_range, + thumb2_bl_out_of_range.o): New rules. + (MOSTLYCLEANFILES): Add arm_bl_in_range, arm_bl_out_of_range, + thumb_bl_in_range, thumb_bl_out_of_range, thumb2_bl_in_range and + thumb2_bl_out_of_range + * testsuite/Makefile.in: Regenerate. + * testsuite/arm_bl_in_range.s: New file. + * testsuite/arm_bl_out_of_range.s: Ditto. + * testsuite/arm_branch_in_range.sh: Ditto. + * testsuite/arm_branch_range.t: Ditto. + * testsuite/thumb2_branch_range.t: Ditto. + * testsuite/thumb_bl_in_range.s: Ditto. + * testsuite/thumb_bl_out_of_range.s: Ditto. + * testsuite/thumb_branch_range.t: Ditto. + +2010-02-20 Sriraman Tallam + + * gc.h (gc_process_relocs): Change vectors to point to the new list. + Add reloc offset information. + * icf.cc (get_section_contents): Change iterators to point to the new + vectors. Add reloc offset information to the contents. + * icf.h (Icf::Sections_reachable_info): New typedef. + (Icf::Sections_reachable_list): New typedef. + (Icf::Offset_info): New typedef. + (Icf::Reloc_info): New struct typedef. + (Icf::Reloc_info_list): New typedef. + (Icf::symbol_reloc_list): Delete method. + (Icf::addend_reloc_list): Delete method. + (Icf::section_reloc_list): Delete method. + (Icf::reloc_info_list): New method. + (Icf::reloc_info_list_): New member. + +2010-02-19 Doug Kwan + + * arm-reloc.def: Mark R_ARM_TLS_GD32, R_ARM_TLS_LDM32, + R_ARM_TLS_LDO32, R_ARM_TLS_IE32 and R_ARM_TLS_LE32 are implemented. + * arm.cc (Arm_relocation_functions): New forward declaration. + (Target_arm::Target_arm): Initialize new data members + got_mod_index_offset_ and tls_base_symbol_defined_. + (Target_arm::Relocate::relocate_tls): New method. + (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, + GOT_TYPE_TLS_PAIR and GOT_TYPE_TLS_DESC. + (Target_arm::got_mod_index_offset_, + Target_arm::tls_base_symbol_defined_): New data members. + (Target_arm::Scan::local, Target::Scan::global, + Target_arm::Relocate::relocate): Handle 32-bit initial TLS + relocations. + +2010-02-18 Doug Kwan + + * arm.cc (Arm_relobj::find_linked_text_section): New method. + (Arm_relobj::make_exidx_input_section): Pass section index of linked + text section as a parameter becuase some broken tools may not set + the link in section header. + (Target_arm::has_got_section): New method. + (Target_arm::scan_section_for_cortex_a8_stubs): Treat an input section + without any mapping symbol as data only. Remove warning. + (Arm_relobj::do_read_synbols): If an EXIDX input section has no + link in its section header, try to discover the link by inspecting the + REL31 relocation at the beginning of the section. + (Target_arm::Scan::check_non_pic): Report name of offending relocation + in error message. + (Target_arm::Scan::global): Treat any reference to the symbol + _GLOBAL_OFFSET_TABLE_ as a GOT access. + +2010-02-12 Sriraman Tallam + + * arm.cc (Scan::local_reloc_may_be_function_pointer): New function. + (Scan::global_reloc_may_be_function_pointer): New function. + * sparc.cc (Scan::local_reloc_may_be_function_pointer): New function. + (Scan::global_reloc_may_be_function_pointer): New function. + * powerpc.cc (Scan::local_reloc_may_be_function_pointer): New function. + (Scan::global_reloc_may_be_function_pointer): New function. + * i386.cc (Scan::local_reloc_may_be_function_pointer): New function. + (Scan::global_reloc_may_be_function_pointer): New function. + * x86_64.cc (Scan::local_reloc_may_be_function_pointer): New function. + (Scan::global_reloc_may_be_function_pointer): New function. + (Scan::possible_function_pointer_reloc): New function. + (Target_x86_64::can_check_for_function_pointers): New function. + * gc.h (gc_process_relocs): Scan relocation types to determine if + function pointers were taken for targets that support it. + * icf.cc (Icf::find_identical_sections): Include functions for + folding in safe ICF whose pointer is not taken. + * icf.h (Secn_fptr_taken_set): New typedef. + (fptr_section_id_): New member. + (section_has_function_pointers): New function. + (set_section_has_function_pointers): New function. + (check_section_for_function_pointers): New function. + * options.h: Fix comment for safe ICF option. + * target.h (can_check_for_function_pointers): New function. + * testsuite/Makefile.am: Add icf_safe_so_test test case. + Modify icf_safe_test for X86-64. + * testsuite/Makefile.in: Regenerate. + * testsuite/icf_safe_so_test.cc: New file. + * testsuite/icf_safe_so_test.sh: New file. + * testsuite/icf_safe_test.cc (kept_func_3): New function. + (main): Change to take pointer to function kept_func_3. + * testsuite/icf_safe_test.sh (arch_specific_safe_fold): Check if safe + folding is done correctly for X86-64. + +2010-02-12 David S. Miller + + * output.h (Output_reloc::Output_reloc): Add + is_symbolless parameter. + (Output_reloc::is_symbolless): New. + (Output_reloc::is_symbolless_): New. + (Output_reloc::type_): Decrease to 29 bits. + (Output_reloc::Output_reloc): Add is_symbolless parameter. + (Output_reloc::is_symbolless): New. + (Output_data_reloc::add_global): Handle is_symbolless. + (Output_data_reloc::add_global_relative): Likewise. + (Output_data_reloc::add_local): Likewise. + (Output_data_reloc::add_local_relative): Likewise. + (Output_data_reloc::add_symbolless_global_addend): New. + (Output_data_reloc::add_symbolless_local_addend): New. + * output.cc (Output_reloc::Output_reloc): Handle + is_symbolless. + (Output_reloc::set_needs_dynsym_index): Test ->is_symbolless_ + instead of ->is_relative_ + (Output_reloc::write): Likewise. + (Output_reloc::get_symbol_index): Return 0 when ->is_symbolless_ + (Output_reloc::write_rel): Simplify. + + * sparc.cc (Target_sparc::Scan::local): Use + ->add_symbolless_local_addend as needed. + (Target_sparc::Scan::global): Use ->add_symbolless_global_addend as + needed. Also, emit appropriate unaligned vs. aligned dynamic reloc + based upon relocation offset. + +2010-02-11 Doug Kwan + + * arm.cc (Target_arm::Scan::local): Fix bugs in relocation handling. + (Target_arm::Scan::global): Ditto. Also remove a comment before the + beginning of function. + (Target_arm::Relocate::relocate): Remove error messages for MOVW_ABS + and MOVT_ABS relocations. Those are non issued in scanning. Fix + parameter is_32bit in calls to should_apply_static_reloc. + * testsuite/Makefile.am (check_SCRIPTS): Add arm_abs_global.sh. + (check_DATA): Add arm_abs_global.stdout. + (arm_abs_lib.o, libarm_abs.so, arm_abs_global.o, arm_abs_global, + arm_abs_global.stdout): New rules. + (MOSTLLYCLEANFILES): Add arm_abs_global + * Makefile.in: Regenerate. + * testsuite/arm_abs_global.s: New file. + * testsuite/arm_abs_global.sh: Ditto. + * testsuite/arm_abs_lib.s: Ditto. + +2010-02-11 Ian Lance Taylor + + * gold.cc (queue_middle_gc_tasks): Use a separate blocker for each + Read_relocs task. + (queue_middle_tasks): Likewise, and also for Scan_relocs. Run + Allocate_commons_task first. + * reloc.cc (Read_relocs::run): Pass next_blocker_ down to next + task, rather than symtab_lock_. + (Gc_process_relocs::~Gc_process_relocs): New function. + (Gc_process_relocs::is_runnable): Check this_blocker_. + (Gc_process_relocs::locks): Use next_blocker_ rather than + blocker_. + (Scan_relocs::~Scan_relocs): New function. + (Scan_relocs::is_runnable): Check this_blocker_ rather than + symtab_lock_. + (Scan_relocs::locks): Drop symtab_lock_ and blocker_. Add + next_blocker_. + * reloc.h (class Read_relocs): Drop symtab_lock_ and blocker_ + fields. Add this_blocker_ and next_blocker_ fields. Adjust + constructor accordingly. + (class Gc_process_relocs): Likewise. + (class Scan_relocs): Likewise. + * common.h (class Allocate_commons_task): Remove symtab_lock_ + field, and corresponding constructor parameter. + * common.cc (Allocate_commons_tasK::is_runnable): Remove use of + symtab_lock_. + (Allocate_commons_task::locks): Likewise. + +2010-02-11 Ian Lance Taylor + + * gold-threads.h (class Once): Define. + (class Initialize_lock): Rewrite as child of Once. + * gold-threads.cc (class Once_initialize): Define. + (once_pointer_control): New static variable. + (once_pointer, once_arg): New static variables. + (c_run_once): New static function. + (Once::Once, Once::run_once, Once::internal_run): New functions. + (class Initialize_lock_once): Remove. + (initialize_lock_control): Remove. + (initialize_lock_pointer): Remove. + (initialize_lock_once): Remove. + (Initialize_lock::Initialize_lock): Move to gold-threads.h. + (Initialize_lock::initialize): Rewrite. + (Initialize_lock::do_run_once): New function. + * archive.cc (Archive::interpret_header): Only clear name if it is + not already empty. + * fileread.cc: Include "gold-threads.h" + (file_counts_lock): New static variable. + (file_counts_initialize_lock): Likewise. + (File_read::release): Only increment counts when using --stats. + Use a lock around the increment. + * parameters.cc (class Set_parameters_target_once): Define. + (set_parameters_target_once): New static variable. + (Parameters::Parameters): Move here from parameters.h. + (Parameters::set_target): Rewrite. + (Parameters::set_target_once): New function. + (Parameters::clear_target): Move here and rewrite. + * parameters.h (class Parameters): Update declarations. Add + set_parameters_target_once_ field. + (Parameters::Parameters): Move to parameters.cc. + (Parameters::clear_target): Likewise. + * readsyms.cc (Read_symbols::do_group): Create a Start_group + task. + (Start_group::~Start_group): New function. + (Start_group::is_runnable): New function. + (Start_group::locks, Start_group::run): New functions. + (Finish_group::run): Change saw_undefined to size_t. + * readsyms.h (class Start_group): Define. + (class Finish_group): Change saw_undefined_ field to size_t. + (Finish_group::Finish_group): Remove saw_undefined and + this_blocker parameters. Change all callers. + (Finish_group::set_saw_undefined): New function. + (Finish_group::set_blocker): New function. + * symtab.h (class Symbol_table): Change saw_undefined to return + size_t. Change saw_undefined_ field to size_t. + * target-select.cc (Set_target_once::do_run_once): New function. + (Target_selector::Target_selector): Initialize set_target_once_ + field. Don't initialize lock_ and initialize_lock_ fields. + (Target_selector::instantiate_target): Rewrite. + (Target_selector::set_target): New function. + * target-select.h (class Set_target_once): Define. + (class Target_selector): Update declarations. Make + Set_target_once a friend. Remove lock_ and initialize_lock_ + fields. Add set_target_once_ field. + +2010-02-10 Ian Lance Taylor + + * dirsearch.cc (Dirsearch::initialize): Add all blockers before + queueing any tasks. + * gold.cc (queue_middle_gc_tasks): Likewise. Fix final blocker. + (queue_middle_tasks): Add all blockers before queueing any tasks. + (queue_final_tasks): Likewise. + * token.h (Task_token::add_blockers): New function. + * object.h (Input_objects::number_of_relobjs): New function. + +2010-02-10 Ian Lance Taylor + + * i386.cc (Relocate::relocate_tls): A local symbol is final if not + shared, not if not position independent. + * x86_64.cc (Relocate::relocate_tls): Likewise. + * testsuite/Makefile.am (check_PROGRAMS): Add tls_pie_pic_test. + (tls_pie_pic_test): New target. + * testsuite/Makefile.in: Rebuild. + + * testsuite/Makefile.am (check_PROGRAMS): Add tls_pie_test. + (tls_test_main_pie.o, tls_test_pie.o): New targets. + (tls_test_file2_pie.o, tls_test_c_pie.o, tls_pie_test): Likewise. + * testsuite/Makefile.in: Rebuild. + +2010-02-09 David S. Miller + + * sparc.cc (Target_sparc::Scan::local): Do not emit relocs other than + R_SPARC_RELATIVE using ->add_local_relative(). + (Target_sparc::Scan::global): Likewise for ->add_global_relative(). + + * output.h (Output_data_dynamic::add_section_size): New method + that takes two Output_data objects. + (Output_data_dynamic::Dynamic_entry): Create storage for secondary + entry param. Handle it in initializers. + * output.cc (Output_data_dynamic::Dynamic_entry::write): For + DYNAMIC_SECTION_SIZE, add in second object size if non-NULL. + * layout.h (Layout::add_target_dynamic_tags): Add dynrel_includes_plt + arg. + * layout.cc (Layout::add_target_dynamic_tags): If dynrel_includes_plt, + and .rela.plt exists, set DT_REL{,A}SZ to sum of .rela.dyn and .rela.plt + * arm.cc (Target_arm::do_finalize_sections): Update to pass false + for dynrel_includes_plt. + * i386.cc (Target_i386::do_finalize_sections): Likewise. + * x86_64.cc (Target_x86_64::do_finalize_sections): Likewise. + * sparc.cc (Target_sparc::make_plt_entry): Force .rela.dyn to be output + before .rela.plt + (Target_sparc::do_finalize_sections): Update to pass true for + dynrel_includes_plt. + * powerpc.cc (Target_powerpc::make_plt_entry): Force .rela.dyn to be + output before .rela.plt + (Target_powerpc::do_finalize_sections): Update to pass true for + dynrel_includes_plt when 32-bit. + +2010-02-08 Doug Kwan + + * arm.cc (Arm_relobj::simple_input_section_output_address): New + method. + (Arm_relobj::section_needs_cortex_a8_stub_scanning, + Arm_relobj::scan_section_for_cortex_a8_stubs, + Arm_relobj::do_relocation_section): Instead of calling + Output_section::output_address, use faster + Arm_relobj::simple_input_section_output_address. + +2010-02-08 David S. Miller + + * sparc.cc (Target_sparc::Relocate::relocate): If relocation offset is + unaligned for R_SPARC_16, R_SPARC_32, or R_SPARC_64, use the unaligned + relocation helper function. + + * sparc.cc (Target_sparc::Scan::local): Handle R_SPARC_GOTDATA_OP* + just like R_SPARC_GOT{10,13,22}. + (Target_sparc::Scan::local): Likewise. + (Target_sparc::Relocate:relocate): Likewise. + +2010-02-06 Ian Lance Taylor + + * configure.ac: Rewrite targetobjs duplicate removal code to use + only shell constructs. + * configure: Rebuild. + +2010-02-05 Doug Kwan + + PR 11247 + * arm.cc (Arm_relobj::section_is_scannable): New method. + (Arm_relobj::section_needs_reloc_stub_scanning): Use it. + (Arm_relobj::section_needs_cortex_a8_stub_scanning): Same. + +2010-02-04 Doug Kwan + + PR 11247 + * arm-reloc-property.cc (cstdio): Include. + * configure.ac (targetobjs): Remove duplicates. + * configure: Regenerate. + * resolve.cc (Symbol_table::resolve): Explicit instantiate both + big and little endian version for a given address size. + +2010-02-03 Doug Kwan + + * arm-reloc-property.cc + (Arm_reloc_property_table::reloc_name_in_error_message): New method + definition. + * arm-reloc-property.h + (Arm_reloc_property_table::get_implemented_static_reloc_property): + New method definition. + (Arm_reloc_property_table::reloc_name_in_error_message): New method + declaration. + * arm-reloc.def (THM_MOVT_ABS, THM_MOVT_PREL, THM_MOVT_BREL): Change + overflow to N. + (GOT_PREL): Change implemented to Y. + * arm.cc (Target_arm::reloc_uses_thumb_bit): Remove method. + (Target_arm::Relocate::reloc_needs_sym_origin): Remove method. + (Arm_relocate_functions::movw_abs_nc): Remove method. + (Arm_relocate_functions::movt_abs): Ditto. + (Arm_relocate_functions::thm_movw_abs_nc): Ditto. + (Arm_relocate_functions::thm_movt_abs): Ditto. + (Arm_relocate_functions::movw_rel_nc): Ditto. + (Arm_relocate_functions::movw_rel): Ditto. + (Arm_relocate_functions::movt_rel): Ditto. + (Arm_relocate_functions:thm_movw_rel_nc): Ditto. + (Arm_relocate_functions:thm_movw_rel): Ditto. + (Arm_relocate_functions:thm_movt_rel): Ditto. + (Arm_relocate_functions::movw, Arm_relocate_functions::movt, + (Arm_relocate_functions::thm_movw, Arm_relocate_functions::thm_movt): + New method definitions. + (Arm_relocation_functions::arm_grp_alu): Add assertion for group index. + (Arm_relocation_functions::arm_grp_ldr): Ditto. + (Arm_relocation_functions::arm_grp_ldrs): Ditto. + (Arm_relocation_functions::arm_grp_ldc): Ditto. + (Target_arm::Relocate::relocate): Check for non-static or + unimplemented relocation code and exit early. Change calls to + Target_arm::reloc_uses_thumb_bit and + Target_arm::Reloc::reloc_needs_sym_origin to use relocation property + instead. Refactor code to handle similar relocations to increase + code sharing. Remove check for unsupported relocation code in switch + statement. + (Target_arm::Relocatable_size_for_reloc::get_size_for_reloc): Use + relocation property table to find out size. Change error message to + print out the name of a relocation code instead of the numeric value. + (Target_arm::scan_reloc_for_stub): Use relocation property table + instead of calling Target_arm::reloc_uses_thumb_bit(). + +2010-02-02 Doug Kwan + + * arm.cc (Target_arm::relocate_section): Do view adjustment for all + types of relaxed input section. + +2010-02-02 Doug Kwan + + * Makefile.am (HFILES): Add arm-reloc-property.h. + (DEFFILES): New. + (TARGETSOURCES): Add arm-reloc-property.cc + (ALL_TARGETOBJS): Add arm-reloc-property.$(OBJEXT) + (libgold_a_SOURCES): $(DEFFILES) + * Makefile.in: Regenerate. + * arm-reloc-property.cc: New file. + * arm-reloc-property.h: New file. + * arm-reloc.def: New file. + * arm.cc: Update comments. + (arm-reloc-property.h): New included header. + (arm_reloc_property_table): New global variable. + (Target_arm::do_select_as_default_target): New method definition. + * configure.tgt (armeb*-*-*,armbe*-*-*,arm*-*-*): Add + arm-reloc-property to targ_extra_obj. + * parameters.cc (set_parameters_target): Call + Target::select_as_default_target(). + * target.h (Target::select_as_default_target): New method definition. + (Target::do_select_as_default_target): Same. + +2010-02-01 Doug Kwan + + * arm.cc (Arm_exidx_fixup::Arm_exidx_fixup): Initialize + first_output_text_section_. + (Arm_exidx_fixup::first_output_text_section): New method definition. + (Arm_exidx_fixup::first_output_text_section_): New data member. + (Arm_exidx_fixup::process_exidx_section): Record the first text + output section seen. + (Arm_output_section::fix_exidx_coverage): Set correct linked section + and entsize in output section header. + +2010-01-29 Viktor Kutuzov + + * gold/arm.cc: Added support for the ARM relocations: R_ARM_THM_PC8, + R_ARM_THM_PC12, R_ARM_THM_ALU_PREL_11_0. + (Arm_relocate_functions::thm_alu11): New Method. + (Arm_relocate_functions::thm_pc8): New Method. + (Arm_relocate_functions::thm_pc12): New Method. + (Target_arm::Scan::local): Handle the relocations. + (Target_arm::Scan::global): Likewise. + (Target_arm::Relocate::relocate): Likewise. + (Target_arm:Relocatable_size_for_reloc::get_size_for_reloc): Likewise. + +2010-01-29 Doug Kwan + + * arm.cc (Target_arm::Scan::global): General PLTs for the same set + of relocation types as ld. + +2010-01-29 Doug Kwan + + * arm.cc (Arm_relocate_functions::arm_branch_common) Change visibility + to public. + (Arm_relocate_functions::thumb_branch_common): Ditto. + (Arm_relocate_functions::thm_call, Arm_relocate_functions::thm_jump24, + Arm_relocate_functions::thm_xpc22, Arm_relocate_functions::plt32, + Arm_relocate_functions::xpc25, Arm_relocate_functions::call, + Arm_relocate_functions::jump24): Remove. + (Target_arm::Relocate::relocate): Adjust code to call + Arm_relocation_functions::arm_branch_common and + Arm_relocation_functions::thumb_branch_common instead of their removed + wrappers. Merge switch-cases together to reduce source code size. + +2010-01-29 Doug Kwan + + * arm.cc (Arm_relobj::Arm_relobj): Initialize new data member + output_local_symbol_count_needs_update_. + (Arm_relobj::output_local_symbol_count_needs_update, + Arm_relobj::set_output_local_symbol_count_needs_update, + Arm_relobj::update_output_local_symbol_count): New methods. + (Arm_relobj::output_local_symbol_count_needs_update_): New data + member. + (Arm_exidx_cantunwind::do_fixed_endian_write): Write address + of pointed function as in a R_ARM_PREL31 relocation. + (Arm_output_section::fix_exidx_coverage): Mark objects + for output local symbol count updating. + (Target_arm::do_relax): Update output local symbol counts in objects + if necessary. + * object.h (Sized_relobj::set_output_local_symbol_count): New method. + +2010-01-29 Viktor Kutuzov + + * arm.cc: Added support for the ARM relocations: + R_ARM_MOVW_BREL_NC, R_ARM_MOVT_BREL, R_ARM_MOVW_BREL, + R_ARM_THM_MOVW_BREL_NC, R_ARM_THM_MOVT_BREL, R_ARM_THM_MOVW_BREL. + (Arm_relocate_functions::movw_rel_nc): Renamed (was + movw_prel_nc). + (Arm_relocate_functions::movw_rel): New method. + (Arm_relocate_functions::movt_rel): Renamed (was movt_prel). + (Arm_relocate_functions::thm_movw_rel_nc): Renamed (was + thm_movw_prel_nc). + (Arm_relocate_functions::thm_movw_rel): New method. + (Arm_relocate_functions::thm_movt_rel): Renamed (was + thm_movt_prel). + (Target_arm::Scan::local): Handle MOVW_BREL/MOVT_BREL + relocations. + (Target_arm::Scan::global): Likewise. + (Target_arm::Relocate::relocate): Likewise. + (Target_arm::Relocatable_size_for_reloc::get_size_for_reloc): + Likewise. + +2010-01-27 Viktor Kutuzov + + * arm.cc: Added support for ARM group relocations. + (Target_arm::reloc_needs_sym_origin): New method. + (Arm_relocate_functions::calc_grp_kn): New method. + (Arm_relocate_functions::calc_grp_residual): New method. + (Arm_relocate_functions::calc_grp_gn): New method. + (Arm_relocate_functions::arm_grp_alu): New Method. + (Arm_relocate_functions::arm_grp_ldr): New Method. + (Arm_relocate_functions::arm_grp_ldrs): New Method. + (Arm_relocate_functions::arm_grp_ldc): New Method. + (Target_arm::Scan::local): Handle the ARM group relocations. + (Target_arm::Scan::global): Likewise. + (Target_arm::Relocate::relocate): Likewise. + (Target_arm::Relocatable_size_for_reloc::get_size_for_reloc): + Likewise. + +2010-01-26 Doug Kwan + + * 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::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 + Relobj::set_section_offset() instead of + Sized_relobj::invalidate_section_offset(). + (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. + (Target_arm::output_section_address_less_than): New type. + (Arm_exidx_fixup::add_exidx_cantunwind_as_needed): Use index of the + linked text section instead of the EXIDX section. + (Arm_output_section::create_stub_group): Add an assertion to check + that this is not an EXIDX output section. + (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. + (Target_arm::do_relax): Fix EXIDX output section coverage in the + first pass. + (Target_arm::fix_exidx_coverage): New method. + * object.h (Relobj::set_output_section): New method. + (Sized_relobj::invalidate_section_offset): Remove method. + (Sized_relobj::do_invalidate_section_offset): Remove method. + (Sized_relobj::do_set_section_offset): Handle offset value -1. + +2010-01-25 Doug Kwan + + * arm.cc (Arm_exidx_merged_section::do_output_offset): + Fix warning due to signed and unsigned comparison on a 32-bit host. + +2010-01-22 Doug Kwan + + * arm.cc (Target_arm::do_relax): Record an output section for section + offset adjustment it contains any stub table that has changed. + * layout.cc (Layout::clean_up_after_relaxation): Adjust section + offsets in an output section if necessary. + * output.cc (Output_section::Output_section): Initialize + section_offsets_need_adjustments_. + (Output_section::add_input_section_for_script): Renamed to + Output_section::add_simple_input_section. + (Output_section::save_states): Add a comment. + (Output_section::discard_states): New method defintion. + (Output_section::adjust_section_offsets): Same. + * output.h (Output_section::add_input_section_for_script): Renamed to + Output_section::add_simple_input_section. + (Output_section::discard_states): New method declaration. + (Output_section::adjust_section_offsets): Same. + (Output_section::section_offsets_need_adjustment, + Output_section::set_section_offsets_need_adjustment): New method + definitions. + (Output_section::section_offsets_need_adjustment_): New data member. + * script-sections.cc + (Output_section_element_input::set_section_address): Adjust code for + renaming of Output_section::add_input_section_for_script. + (Orphan_output_section::set_section_address): Same. + +2010-01-22 Viktor Kutuzov + + * gold/arm.cc (Target_arm): Updated fix_v4bx method and usage of + Fix_v4bx enum values . + * gold/options.h (General_options): New option definitions. + (General_options::fix_v4bx): New method. + (General_options::Fix_v4bx): New enum. + * gold/options.cc (General_options::parse_fix_v4bx): New method. + (General_options::parse_fix_v4bx_interworking): New method. + +2010-01-22 Doug Kwan + + * arm.cc (Arm_exidx_fixup): New class. + +2010-01-21 Doug Kwan + + * arm.cc (Arm_exidx_cantunwind, Arm_exidx_merged_section): New + classes. + (Arm_exidx_section_offset_map): New type. + +2010-01-21 Doug Kwan + + * arm.cc (Arm_exidx_input_section): New class. + (Arm_relobj::exidx_input_section_by_link, + Arm_relobj::exidx_input_section_by_shndx, + Arm_relobj::make_exidx_input_section): New methods. + (read_arm_attributes_section): Remove. + (Arm_relobj::do_read_symbols): Look for ARM.exidx sections and record + information about them. + (Arm_dynobj::do_read_symbols): Move code in read_arm_attributes_section + to here. + +2010-01-20 Doug Kwan + + * arm.cc (Target_arm::Arm_input_section_map): Change key type from + Input_section_specifier to Section_id. + (Target_arm::new_arm_input_section: Adjust code for change of key + type. + (Target_arm::find_arm_input_section): Ditto. + * gc.h (object.h): Include for Section_id nand Section_id_hash. + (Section_id): Remove. + (Garbage_collection::Section_id_hash): Remove. + * icf.h (object.h): Include for Section_id nand Section_id_hash. + (Section_id): Remove. + (Icf::Section_id_hash): Remove. + * object.h (Section_id, Const_section_id, Section_id_hash, + Const_section_id_hash): New type definitions. + * output.cc (Output_section::add_relaxed_input_section): Change to + use Const_section_id instead of Input_section_specifier as key type. + (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): + 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_relaxed_input_section): Ditto. + * output.h (Input_section_specifier): Remove class. + (Output_section::Output_section_data_by_input_section_map): Change + key type to Const_section_id. + (Output_section::Output_relaxed_input_section_by_input_section_map): + Ditto. + (Output_section::Relaxation_map): Change key type to Section_id. + +2010-01-20 Viktor Kutuzov + + * gold/arm.cc: Added support for R_ARM_V4BX relocation + (class Arm_v4bx_stub): New class. + (DEF_STUBS): Updated definition to support v4_veneer_bx. + (Stub_factory::make_arm_v4bx_stub): New method. + (Stub_factory::elf32_arm_stub_v4_veneer_bx): New veneer template. + (Stub_table::empty): Handle v4bx stubs. + (Stub_table::add_arm_v4bx_stub): New method. + (Stub_table::find_arm_v4bx_stub): New method. + (Arm_relocate_functions::v4bx): New method. + (Target_arm::fix_v4bx): New method. + (Target_arm::Target_arm): Handle R_ARM_V4BX. + (Stub_table::relocate_stubs): Likewise. + (Stub_table::do_write): Likewise. + (Stub_table::update_data_size_and_addralign): Likewise. + (Stub_table::finalize_stubs): Likewise. + (Target_arm::Scan::local): Likewise. + (Target_arm::Scan::global): Likewise. + (Target_arm::do_finalize_sections): Likewise. + (Target_arm::Relocate::relocate): Likewise. + (Target_arm::Relocatable_size_for_reloc::get_size_for_reloc): + Likewise. + (Target_arm::scan_reloc_for_stub): Likewise. + (Target_arm::scan_reloc_section_for_stubs): Likewise. + +2010-01-19 Ian Lance Taylor + + * output.cc (Output_section_headers::do_sized_write): Write large + segment count to sh_info field. + (Output_file_header::do_sized_write): For large segment count, + write PN_XNUM to e_phnum field. + +2010-01-15 Viktor Kutuzov + + * arm.cc (Arm_relocate_functions::thm_jump6): New function. + (Arm_relocate_functions::thm_jump8): New function. + (Arm_relocate_functions::thm_jump11): New function. + (Target_arm::Scan::local): Handle R_ARM_THM_JUMP6, R_ARM_THM_JUMP8, + R_ARM_THM_JUMP11. + (Target_arm::Scan::global): Likewise. + (Target_arm::Relocate::relocate): Likewise. + (Target_arm::Relocatable_size_for_reloc::get_size_for_reloc): + Likewise. + +2010-01-14 Doug Kwan + + * arm.cc (map, utility): Include headers. + (Target_arm::apply_cortex_a8_workaround): New method. + (Arm_relobj::do_relocate_sections): Apply any Cortex-A8 workaround. + (Target_arm::Scan::local): Handle R_ARM_THM_JUMP24, R_ARM_THM_JUMP19. + (Target_arm::Scan::global): R_ARM_THM_JUMP19. + (Target_arm::do_finalize_sections): Set fix_cortex_a8_ according to + the --[no-]fix-cortex-a8 command line options. + (Target_arm::Relocate::relocate): Handle R_ARM_JUMP19. + (Target_arm::relocate_stub): Use addend in instruction template. + * options.h (DEFINE_bool): Set the user-set flag. + (General_options): Add --[no-]-fix-cortex options. + * output.cc (Output_section::convert_input_sections_to_relaxed_sections) + : Update fast look-up map after conversion. + +2010-01-14 Sriraman Tallam + + * object.cc (Sized_relobj::do_layout): Change to call layout_gnu_stack + in the first pass of do_layout. + +2010-01-13 Doug Kwan + + * arm.cc (Arm_relobj::section_needs_reloc_stub_scanning, + Arm_relobj::scan_sections_for_stubs): Rearrange code to avoid an + apparent compiler problem of not folding static constant integral + data members of elfcpp::Elf_sizes<32>. + +2010-01-13 Doug Kwan + + * arm.cc (Arm_relobj::section_needs_reloc_stub_scanning, + Arm_relobj::section_needs_cortex_a8_stub_scanning, + Arm_relobj::scan_section_for_cortex_a8_erratum, + Arm_relobj::scan_span_for_cortex_a8_erratum): New methods. + (Arm_relobj::scan_sections_for_stubs): Move code deciding what + sections to scan for relocation stubs into a new method + Arm_relobj::section_needs_reloc_stub_scanning. Handle both + relocation and Cortex-A8 stub scanning. + (Target_arm::do_relax): Force stubs to be after stubbed sections + if fixing the Cortex-A8 erratum. Remove all Cortex-A8 stubs at + the beginning of a new relaxation pass. Update a comment. + (Target_arm::scan_span_for_cortex_a8_erratum): New method definition. + +2010-01-12 Ian Lance Taylor + + * target-reloc.h (visibility_error): New inline function. + (relocate_section): Call visibility_error. + * testsuite/Makefile.am (check_DATA): Add protected_3.err. + (MOSTLYCLEANFILES): Likewise. + (protected_4_pic.o, protected_3.err): New targets. + * testsuite/protected_4.cc: New file. + +2010-01-12 Doug Kwan + + * arm.cc (Cortex_a8_reloc): New class. + (Target_arm::Target_arm): Initialize new data members fix_cortex_a8_ + and cortex_a8_relocs_info_. + (Target_arm::fix_cortex_a8): New method definition. + (Target_arm::Cortex_a8_relocs_info): New type. + (Target_arm::fix_cortex_a8_, Target_arm::cortex_a8_relocs_info_): + New data member declarations. + (Target_arm::scan_reloc_for_stub): Record information about + relocations for THUMB branches that might be exempted from the + Cortex-A8 workaround. + (Target_arm::do_relax): Clear all Cortex-A8 relocation information + at the beginning of a relaxation pass. + +2010-01-12 Doug Kwan + + * arm.cc (Arm_relobj::mapping_symbols_info_): New data member. + (Arm_relobj::Mapping_symbol_position, + Arm_reloj::Mapping_symbol_position_less, + Arm_relobj::Mapping_symbols_info): New types. + (Target_arm::is_mapping_symbol_name): New method definition. + (Arm_relobj::do_count_local_symbols): Save information about mapping + symbols. + +2010-01-11 Doug Kwan + + * arm.cc (Arm_relocate_functions::thumb32_branch_offset, + Arm_relocate_functions::thumb32_branch_upper, + Arm_relocate_functions::thumb32_branch_lower, + Arm_relocate_functions::thumb32_cond_branch_offset, + Arm_relocate_functions::thumb32_cond_branch_upper, + Arm_relocate_functions::thumb32_cond_branch_lower, + Arm_relocate_functions::thm_jump19): New methods to handle THUMB + branch offset encoding. + (Arm_relocate_functions::thumb_branch_common): Use new branch + offset encoding methods to avoid code duplication. + (Stub_template::Stub_template) Handle THUMB16_SPECIAL_TYPE. + (Stub_addend_reader::operator()): Use new branch encoding method + to avoid code duplication. + +2010-01-11 Doug Kwan + + * arm.cc (Arm_relobj::do_gc_process_relocs): New method. + (Target_arm::do_finalize_sections): Define special EXIDX section + symbols only if referenced. + * gc.h (Garbage_collection::add_reference): New method. + (gc_process_relocs): Use Garbage_collection::add_reference to avoid + code duplication. + +2010-01-11 Ian Lance Taylor + + * script.cc (Version_script_info::build_expression_list_lookup): + Change complaing about duplicate wildcard match from error to + warning. + + * script.cc (class Lazy_demangler): Recreate--revert part of patch + of 2009-12-30. + (Version_script_info::Version_script_info): Initialize globs_, + default_version_, default_is_global_, and exact_. Don't + initialize globals_ or locals_. + (Version_script_info::build_lookup_tables): Build local symbols + first. + (Version_script_info::unquote): New function. + (Version_script_info::add_exact_match): New function. + (Version_script_info::build_expression_list_lookup): Remove lookup + parameter. Add is_global parameter. Change all callers. Handle + wildcard pattern specially. Unquote pattern. Call + add_exact_match. + (Version_script_info::get_name_to_match): New function. + (Version_script_info::get_symbol_version): New function. + (Version_script_info::get_symbol_version_helper): Remove. + (Version_script_info::check_unmatched_names): Call unquote. + * script.h (class Version_script_info): Change get_symbol_version + to be non-inline and add is_global parameter; change all callers. + Rewrite symbol_is_local. Update declarations. Define struct + Version_tree_match, Exact, Globs. Don't define struct Lookup. + Remove globals_ and locals_ members. Add exact_, globs_, + default_version_, is_global_. + (Version_script_info::Glob): Remove pattern, add expression and + is_global. Update constructor. Change all callers. + * dynobj.cc (Versions::finalize): Mark the version symbol as the + default version. + (Versions::symbol_section_contents): If a symbol is undefined, or + defined in a dynamic object, set the version index to + VER_NDX_LOCAL. + * symtab.cc (Symbol_table::add_from_relobj): Don't call + symbol_is_local. + (Symbol_table::add_from_pluginobj): Likewise. + * testsuite/ver_matching_test.sh: blaza1 and blaza go into V2. + +2010-01-11 Doug Kwan + + * Makefile.am (incremental_dump_DEPENDENCIES): Add libintl dependency. + (incremental_dump_LDADD): Add linking option for libintl. + * Makefile.in: Regenerate. + +2010-01-11 H.J. Lu + + PR gold/11144 + * testsuite/Makefile.am (dynamic_list.stdout): Use --dyn-syms + instead of -Ds. + * testsuite/Makefile.in: Regenerated. + +2010-01-10 Doug Kwan + + * options.h (DEFINE_var): Use parentheses around argument varname__ + in macro body to avoid any unintended subsequent substitutions. + +2010-01-10 Ian Lance Taylor + + * resolve.cc (Symbol_table::resolve): Add symbols to list of ODR + candidates before doing symbol resolution. + + * resolve.cc (Symbol_table::resolve): Add symbols to the list of + ODR candidates if only one is weak. + +2010-01-08 Ian Lance Taylor + + * script.cc (Version_script_info::build_expression_list_lookup): + Don't warn about ambiguous version, just record the ambiguity. + (Version_script_info::get_symbol_version_helper): Give error if + version is ambiguous. + +2010-01-08 Doug Kwan + + * arm.cc (Stub_table::Stub_table): Initalize cortex_a8_stubs_, + prev_data_size_ and prev_addralign_. Remove initializer for + deleted data member has_been_changed_. + (Stub_table::empty): Look at both reloc_stubs_ and cortex_a8_stubs_ + to determine if the table is empty. + (Stub_table::has_been_changed, Stub_table_set_has_been_changed): + Remove. + (Stub_table::add_reloc_stub): Define method in class definition + instead of just declaring it there. + (Stub_table::add_cortex_a8_stub): New method definition. + (Stub_table::update_data_size_and_addralign): Ditto. + (Stub_table::finalize_stubs): Ditto. + (Stub_table::apply_cortex_a8_workaround_to_address_range): Ditto. + (Stub_table::do_addralign_): Return address alignment in the + (Stub_table::do_reset_address_and_file_offset): Define method in + class definition instead of declaring it there. Set current data + size to be the data size of the previous pass. + (Stub_table::set_final_data_size): Use current data size as the + final data size. + (Stub_table::relocate_stub): Change parameter type of stub from + Reloc_stub pointer to Stub pointer. + (Stub_table::addralign_, Stub_table::has_been_changed_): Remove. + (Stub_table::Cortex_a8_stub_list): New typedef. + (Stub_table::cortex_a8_stubs_, Stub_table::prev_data_size_, + Stub_table::prev_addralign_): New data member. + (Arm_relobj::Arm_relobj): Initialize data member + section_has_cortex_a8_workaround_. + (Arm_relobj::section_has_cortex_a8_workaround, + Arm_relobj::mark_section_for_cortex_a8_workaround): New method + definitions. + (Arm_relobj::section_has_cortex_a8_workaround_): New data member + declarations. + (Target_arm::relocate_stub): Change parameter type of stub from + Reloc_stub pointer to Stub pointer. + (Insn_template::size, Insn_template::alignment): Handle + THUMB16_SPECIAL_TYPE. + (Stub_table::remove_all_cortex_a8_stubs, Stub_table::finalize_stubs, + 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::do_write): Ditto. + (Target_arm::do_relax): Adjust code for changes in Stub_table. + +2010-01-08 Ian Lance Taylor + + PR 11108 + * symtab.h (class Symbol): Remove fields is_target_special_ and + has_plt_offset_. Add field is_defined_in_discarded_section_. + (Symbol::is_defined_in_discarded_section): New function. + (Symbol::set_is_defined_in_discarded_section): New function. + (Symbol::has_plt_offset): Rewrite. + (Symbol::set_plt_offset): Verify that new offset is not -1U. + * symtab.cc (Symbol::init_fields): Initialize plt_offset_ to -1U. + Don't initialize is_target_special_ or has_plt_offset_. + Initialize is_defined_in_discarded_section_. + (Symbol_table::add_from_relobj): If appropriate, set + is_defined_in_discarded_section. + * resolve.cc (Symbol::override_base_with_special): Don't test + is_target_special_. Change has_plt_offset_ to has_plt_offset(). + * target-reloc.h (relocate_section): Do special handling for + symbols defined in discarded sections for global symbols as well + as local symbols. + +2010-01-08 Ian Lance Taylor + + * dynobj.cc (big_endian>::find_dynsym_sections): Set pi to NULL in + the SHT_SYMTAB case. + +2010-01-08 Ian Lance Taylor + + * object.cc (Sized_relobj::do_layout): Don't get confused if + layout_eh_frame returns NULL. + +2010-01-08 Ian Lance Taylor + + PR 11084 + * dynobj.cc (Sized_dynobj::find_dynsym_sections): If there is no + dynamic symbol table, use the normal symbol table. + (Sized_dynobj::do_read_symbols): Remove assertion about type of + symbol table. + +2010-01-08 Ian Lance Taylor + + PR 11072 + * layout.cc (Layout::include_section): Remove .gnu_debuglink + sections. + +2010-01-08 H.J. Lu + + * version.cc (print_version): Change to "Copyright 2010". + +2010-01-08 Ian Lance Taylor + + PR 10287 + PR 11063 + * i386.cc (class Target_i386): Change return type of plt_section + to be non-const. + (class Output_data_plt_i386): Add tls_desc_rel_ field. + (Output_data_plt_i386::Output_data_plt_i386): Initialize + tls_desc_rel_ field. + (Output_data_plt_i386::rel_tls_desc): New function. + (Target_i386::rel_tls_desc_section): New function. + (Target_i386::Scan::local): Rewrite R_386_TLS_GOTDESC handling. + (Target_i386::Scan::global): For R_386_TLS_GOTDESC put + R_386_TLS_DESC reloc in rel_tls_desc_section. + * x86_64.cc (class Target_x86_64): Add tlsdesc_reloc_info_ field. + Define struct Tlsdesc_info. + (Target_x86_64::Target_x86_64): Initialize tlsdesc_reloc_info_. + (Target_x86_64::do_reloc_symbol_index): New function. + (Target_x86_64::add_tlsdesc_info): New function. + (class Output_data_plt_x86_64): Add tlsdesc_rel_ field. + (Output_data_plt_x86_64::Output_data_plt_x86_64): Initialize + tlsdesc_rel_ field. + (Output_data_plt_x86_64::rela_plt): Rename from rel_plt. Change + all callers. + (Output_data_plt_x86_64::rela_tlsdesc): New function. + (Target_x86_64::rela_tlsdesc_section): New function. + (Target_x86_64::Scan::local): Rewrite R_X86_64_GOTPC32_TLSDESC + handling. + (Target_x86_64::Scan::global): For R_X86_64_GOTPC32_TLSDESC put + (Target_x86_64::do_reloc_addend): New function. + R_X86_64_TLSDESC reloc in rela_tlsdesc_section. + * output.h (class Output_reloc) [SHT_REL]: Add new constructor + declarations. Define TARGET_CODE. Add arg field to u1_ union. + (Output_reloc::type): New function. + (Output_reloc::is_local_section_symbol): Check for TARGET_CODE. + (Output_reloc::is_target_specific): New function. + (Output_reloc::target_arg): New function. + (class Output_reloc) [SHT_RELA]: Add four new constructors for + absolute relocs and target specific relocs. + (class Output_data_reloc) [SHT_REL]: Add add_absolute and + add_target_specific. + (class Output_data_reloc) [SHT_RELA]: Likewise. + * output.cc (Output_reloc::Output_reloc): Add four new versions + for absolute relocs and target specific relocs. + (Output_reloc::set_needs_dynsym_index): Add TARGET_CODE case. + (Output_reloc::get_symbol_index): Likewise. + (Output_reloc::local_section_offset): Check that local_sym_index_ + is not TARGET_CODE or 0. + (Output_reloc::symbol_value): Likewise. + (Output_reloc::write) [SHT_RELA]: Call target for target specific + reloc. + * target.h (class Target): Add reloc_symbol_index and reloc_addend + functions. Add do_reloc_symbol_index and do_reloc_addend virtual + functions. + * layout.cc (add_target_dynamic_tags): Use output section for + DT_PLTRELSZ and DT_JMPREL. + +2010-01-07 Ian Lance Taylor + + PR 11061 + * output.h (class Output_reloc) [SHT_RELA]: Add is_relative + function. + (class Output_data_reloc_generic): Define. + (class Output_data_reloc_base): Change base class to + Output_data_reloc_generic. Change add() method to call + bump_relative_reloc_count for a relative reloc. Remove + sort_relocs_ field. + * output.cc (Output_data_reloc_base::do_write): Change sort_reloc_ + to sort_relocs(). + * layout.cc (Layout::add_target_dynamic_tags): Change dyn_rel to + Output_data_reloc_generic*. Add DT_RELCOUNT/DT_RELACOUNT tag if + appropriate. + * layout.h (class Layout): Update declaration. + +2010-01-07 Ian Lance Taylor + + * output.h (class Output_data): Add const version of + output_section and do_output_section. + (class Output_section_data): Add const version of + do_output_section. + (class Output_section): Likewise. + * layout.cc (Layout::add_target_dynamic_tags): New function. + * layout.h (class Layout): Update declarations. + * arm.cc (Target_arm::do_finalize_sections): Use + add_target_dynamic_tags. + * i386.cc (Target_i386::do_finalize_sections): Likewise. + * powerpc.cc (Target_powerpc::do_finalize_sections): Likewise. + * sparc.cc (Target_sparc::do_finalize_sections): Likewise. + * x86_64.cc (Target_x86_64::do_finalize_sections): Likewise. + +2010-01-07 Ian Lance Taylor + + PR 11042 + * copy-relocs.cc (Copy_relocs::emit_copy_reloc): Mark the dynamic + object as needed. + +2010-01-07 Dmitry Gorbachev + Ian Lance Taylor + + PR 11019 + * object.cc: Instantiate Xindex::initialize_symtab_xindex and + Xindex::read_symtab_xindex. + +2010-01-07 Doug Kwan + + * arm.cc (Insn_template::Type): New enum value THUMB16_SPECIAL_TYPE. + (Insn_template::thumb16_bcond_insn): New method declaration. + (Insn_template): Fix spelling. + (Stub::thumb16_special): New method declaration. + (Stub::do_write): Define virtual method which was previously pure + virtual. + (Stub::do_thumb16_special): New method declaration. + (Stub::do_fixed_endian_write): New template member. + (Reloc_stub::do_write): Remove. + (Reloc_stub::do_fixed_endian_write): Remove. + (Cortex_a8_stub): New class definition. + (Stub_factory::make_cortex_a8_stub): New method definition. + (Stub_factory::Stub_factory): Add missing static storage class + qualifier for elf32_arm_stub_a8_veneer_blx. + +2010-01-07 Ian Lance Taylor + + PR 10980 + * options.h (class General_options): Add --warn-unresolved-symbols + and --error-unresolved-symbols. + * errors.cc (Errors::undefined_symbol): Implement + --warn-unresolved-symbols. + + * options.h (class General_options): Add -z text and -z textoff. + * layout.cc (Layout::finish_dynamic_section): Implement -z text. + +2010-01-06 Sriraman Tallam + + * gc.h (Garbage_collection::Cident_section_map): New typedef. + (Garbage_collection::cident_sections): New function. + (Garbage_collection::add_cident_section): New function. + (Garbage_collection::cident_sections_): New member. + (gc_process_relocs): Add references to sections whose names are C + identifiers. + * gold.h (cident_section_start_prefix): New constant. + (cident_section_stop_prefix): New constant. + (is_cident): New function. + * layout.cc (Layout::define_section_symbols): Replace string constants + with the newly defined constants. + * object.cc (Sized_relobj::do_layout): Track sections whose names are + C identifiers. + * testsuite/Makefile.am: Add gc_orphan_section_test. + * testsuite/Makefile.in: Regenerate. + * testsuite/gc_orphan_section_test.cc: New file. + * testsuite/gc_orphan_section_test.sh: New file. + +2010-01-06 Ian Lance Taylor + + PR 10980 + * options.h (class General_options): Add --warn-shared-textrel. + * layout.cc (Layout::finish_dynamic_section): Implement + --warn-shared-textrel. + + PR 10980 + * options.h (class General_options): Add --warn-multiple-gp. + +2010-01-06 Viktor Kutuzov + + * Makefile.am (incremental_dump_DEPENDENCIES): Remove + $(THREADSLIB) and $(LIBDL). + * Makefile.in: Rebuild. + +2010-01-06 Ian Lance Taylor + + PR 10980 + * options.cc (General_options::parse_section_start): New function. + (General_options::section_start): New function. + (General_options::General_options): Initialize all members. + * options.h: Include + (class General_options): Add --section-start. Add section_starts_ + member. + * layout.cc (Layout::attach_allocated_section_to_segment): If + --section-start was used, set the address of the segment. Remove + local sort_sections. + (Layout::relaxation_loop_body): If the address of the load segment + has been set by --section-start, don't use it. + * output.h (Output_segment::update_flags_for_output_section): New + function. + * output.cc (Output_segment::add_output_section): Call + update_flags_for_output_section. + +2010-01-05 Ian Lance Taylor + + PR 10980 + * options.h (class General_options): Add --undefined-version. + * script.cc (struct Version_expression): Add was_matched_by_symbol + field. + (Version_script_info::matched_symbol): New function. + (Version_script_info::get_symbol_version_helper): Call + matched_symbol. + (Version_script_info::check_unmatched_names): New function. + * script.h (class Version_script_info): Update declarations. + * gold.cc (queue_middle_tasks): Handle --no-undefined-version. + + * options.h (class General_options): Use DEFINE_bool_alias for + allow_multiple_definition. + * resolve.cc (Symbol_table::should_override): Don't test + allow_multiple_definition. + + PR 10980 + * options.h (class General_options): Add --cref. + * main.cc (main): Print cref table if --cref. Don't close mapfile + until after printing cref table. + * cref.cc: Include "symtab.h". + (class Cref_inputs): Define Cref_table_compare and Cref_table. + (Cref_table_compare::operator()): New function. + (Cref_inputs::gather_cref): New function. + (filecol): New static const. + (Cref_inputs::print_cref): New function. + (Cref::print_cref): New function. + * cref.h: Include . + (class Cref): Update declarations. + * mapfile.h (Mapfile::file): New function. + * object.h (class Object): Define Symbols. Declare virtual + do_get_global_symbols. + (Object::get_global_symbols): New function. + * object.cc (Input_objects::add_object): Pass object to cref_ if + --cref. + (Input_objects::archive_start): Likewise. + (Input_objects::archive_stop): Likewise. + (Input_objects::print_cref): New function. + * dynobj.h (Sized_dynobj::do_get_global_symbols): New function. + * dynobj.cc (big_endian>::do_add_symbols): Create symbols_ if + --cref. + * plugin.cc (Sized_pluginobj::do_get_global_symbols): New + function. + * plugin.h (class Sized_pluginobj): Update declarations. + +2010-01-05 Ian Lance Taylor + + * symtab.cc (Symbol_table::add_from_object): Rename def parameter + to is_default_version. Rename insdef to insdefault. + (Symbol_table::add_from_relobj): Rename def to is_default_version + and local to is_forced_local. + (Symbol_table::add_from_pluginobj): Likewise. + (Symbol_table::add_from_dynobj): Likewise. + (Symbol_table::define_special_symbol): Rename insdef to + insdefault. + +2010-01-04 Ian Lance Taylor + + PR 10980 + * options.h (class General_options): Add + --allow-multiple-definition and -z muldefs. + * resolve.cc (Symbol_table::should_override): Don't warn about a + multiple symbol definition if --allow-multiple-definition or -z + muldefs. + + PR 10980 + * options.h (class General_options): Add --add-needed and + --copy-dt-needed-entries. Tweak --as-needed help entry. + * object.cc (Input_objects::check_dynamic_dependencies): Give an + error if --copy-dt-needed-entries aka --add-needed is used and + would cause a change in behaviour. + + PR 10980 + * options.h (class General_options): Add -G as a short version of + --shared. Add no-op options -assert, -g, and -i. + +2010-01-04 Sriraman Tallam + + * gc.h (gc_process_relocs): Call is_section_foldable_candidate to + check for .text or .gnu.linkonce.t sections. + * icf.cc (Icf::find_identical_sections): Ditto. + Change the detection for mangled function name within the section + name. + * icf.h (is_section_foldable_candidate): New function. + +2009-12-30 Ian Lance Taylor + + PR 10980 + * options.h (class General_options): Permit two dashes with + --retain-symbols-file. + +2009-12-30 Ian Lance Taylor + + PR 10979 + * layout.cc (Layout::relaxation_loop_body): If -Ttext was used, + don't put the file header and segment headers in the text + segment. + + PR 10979 + * common.cc (Sort_commons::operator()): Stabilize sort when both + entries are NULL. + (Symbol_table::do_allocate_commons_list): When allocating common + symbols, skip a symbol which is no longer common. + * symtab.h (Symbol::is_common): Test whether the symbol comes from + an object before checking its type. + * testsuite/common_test_2.c: New file. + * testsuite/common_test_3.c: New file. + * testsuite/Makefile.am (check_PROGRAMS): Add common_test_2. + (common_test_2_SOURCES, common_test_2_DEPENDENCIES): Define. + (common_test_2_LDFLAGS, common_test_2_LDADD): Define. + (common_test_2_pic.o, common_test_2.so): New targets. + (common_test_3_pic.o, common_test_3.so): New targets. + * testsuite/Makefile.in: Rebuild. + + PR 10979 + * script.cc (read_input_script): If we see a new SECTIONS clause, + and we have added an input section, give an error. + * layout.h (class Layout): Add have_added_input_section function. + Add have_added_input_section_ field. + * layout.cc (Layout::Layout): Initialize + have_added_input_section_. + (Layout::layout): Set have_added_input_section_. + (Layout::layout_eh_frame): Likewise. + +2009-12-30 Ian Lance Taylor + + PR 10931 + * options.h (class General_options): Add --sort-common option. + * symtab.h (class Symbol_table): Define Sort_commons_order enum. + * common.cc (Sort_common): Add sort_order parameter to + constructor. Add sort_order_ field. + (Sort_commons::operator): Check sort_order_. + (Symbol_table::allocate_commons): Determine the sort order. + (Symbol_table::do_allocate_commons): Add sort_order parameter. + Change all callers. + (Symbol_table::do_allocate_commons_list): Likewise. + +2009-12-30 Ian Lance Taylor + + PR 10916 + * symtab.cc (Symbol_table::add_from_relobj): When not exporting + symbols from this object, don't change the visibility of an + undefined symbol. + * testsuite/exclude_libs_test_1.c (lib1_ref): New function. + +2009-12-30 Ian Lance Taylor + + PR 10861 + * script.h (class Version_script_info): Define Language enum. + Update declarations. Define Glob, Exact, and Lookup types. Add + new fields globals_, locals_, and is_finalized_. + * script.cc: Various formatting fixes. + (class Parser_closure): Change language_stack_ from a vector of + std::string to one of Version_script_info::Language. Adjust all + uses accordingly. + (class Lazy_demangler): Remove. + (struct Version_expression): Change language from std::string to + Version_script_info::Language. + (Version_script_info::Version_script_info): New function. + (Version_script_info::~Version_script_info): Don't call clear. + (Version_script_info::finalize): New function. + (Version_script_info::build_lookup_tables): New function. + (Version_script_info::build_expression_list_lookup): New + function. + (Version_script_info::get_symbol_version_helper): Rewrite to use + lookup tables. + (Version_script_info::print_expression_list): Adjust to use + Version_script_info::Language. + (script_push_lex_into_version_mode): Check that the version script + has not been finalized. + (version_script_push_lang): Change language string to + Version_script_info::Language. + * options.cc (Command_line::version_script): New function. + * options.h (class General_options): Add finalize_dynamic_list + function. Change version_script from declaration to definition. + * testsuite/ver_test_4.script: Remove duplicate def of t2_2. + * testsuite/version_script.map: Remove duplicate def of foo. + * testsuite/Makefile.am (ver_matching_def.so): Depend upon + version_script.map. + * testsuite/Makefile.in: Rebuild. + +2009-12-30 Ian Lance Taylor + + PR 10843 + * target-reloc.h (relocate_for_relocatable): When copying a reloc, + if the input symbol index is 0, make the output symbol index 0. + +2009-12-30 Ian Lance Taylor + + PR 10670 + * options.h (class General_options): Add -x/--discard-all. + * object.cc (Sized_relobj::do_count_local_symbols): Handle + --discard-all. If the local symbol needs a dynamic entry, check + that before handling --discard-locals. + +2009-12-30 Ian Lance Taylor + + PR 10450 + * output.cc (Output_segment::Output_segment): If PT_TLS, set the + flags to PF_R. + (Output_segment::add_output_section): Don't change the flags if + the type is PT_TLS. + + PR 10450 + * dynobj.cc (Dynobj::create_gnu_hash_table): Add symbols to the + GNU hash table if they need a dynamic value. Otherwise, don't add + them if they are defined in a dynamic object or are forced local. + +2009-12-29 Ian Lance Taylor + + PR 10450 + * layout.cc (Layout::create_dynamic_symtab): Only set entsize of + .gnu.hash table for a 32-bit target. + + PR 10450 + * symtab.h (Symbol::needs_dynsym_entry): A symbol in both a + regular and a dynamic object only needs a dynamic symbol table + entry if it is externally visible. + + PR 10450 + * i386.cc (class Target_i386): Initialize global_offset_table_ in + constructor. Add global_offset_table_ field. + (Target_i386::got_section): Set global_offset_table_. + (Target_i386::do_finalize_sections): Set global_offset_table_ + size. + * x86_64.cc (class Target_x86_64): Initialize global_offset_table_ + in constructor. Add global_offset_table_ field. + (Target_x86_64::got_section): Set global_offset_table_. + (Target_x86_64::do_finalize_sections): Set global_offset_table_ + size. + + * layout.cc (Layout::Layout): Initialize increase_relro_. + (Layout::get_output_section): Add is_relro, is_last_relro, and + is_first_non_relro parameters. Change all callers. + (Layout::choose_output_section): Likewise. + (Layout::add_output_section_data): Likewise. + (Layout::make_output_section): Likewise. + (Layout::set_segment_offsets): Clear increase_relro when using a + linker script. + * layout.h (class Layout): Add increase_relro method. Add + increase_relro_ field. Update declarations. + * output.cc (Output_section::Output_section): Initialize + is_last_relro_ and is_first_non_relro_. + (Output_segment::add_output_section): Group relro sections is + do_sort is true. Handle is_last_relro and is_first_non_relro. + (Output_segment::maximum_alignment): Remove relro handling. + (Output_segment::set_section_addresses): Add increase_relro + parameter. Change all callers. Add initial alignment to align + relro sections on separate page. Remove old relro handling. + (Output_segment::set_section_list_addresses): Remove in_relro + parameter. Change all callers. + (Output_segment::set_offset): Add increase parameter. Change all + callers. Remove old relro handling. + * output.h (class Output_section): Add new methods: is_last_relro, + set_is_last_relro, is_first_non_relro, set_is_first_non_relro. + Add is_last_relro_ and is_first_non_relro_ fields. + * i386.cc (Target_i386::got_section): Don't call set_is_relro. + Create separate .got.plt section. Call increase_relro. + * x86_64.cc (Target_x86_64::got_section): Likewise. + * testsuite/relro_script_test.t: Add .got.plt. + + PR 10450 + * layout.cc (Layout::Layout): Initialize dynamic_symbol_ field. + (Layout::create_initial_dynamic_sections): Set dynamic_symbol_. + (Layout::finalize): Call set_dynamic_symbol_size. + (Layout::set_dynamic_symbol_size): New function. + * layout.h (class Layout): Add dynamic_symbol_ field. Declare + set_dynamic_symbol_size. + + PR 10450 + * output.h (class Output_section): Add is_entsize_zero_ field. + * output.cc (Output_section::Output_section): Initialize + is_entsize_zero_. + (Output_section::set_entsize): If two different entsizes are + requested, force it to zero. + (Output_section::add_input_section): Set flags for .debug_str + before updating section flags. Set entsize. + (Output_section::update_flags_for_input_section): Set SHF_MERGE + and SHF_STRING if all input sections have those flags. + +2009-12-29 Rafael Espindola + + * main.cc (main): Fix the sys time reporting. + * workqueue.cc (Workqueue::find_and_run_task): Fix the sys time + reporting. + +2009-12-29 Sriraman Tallam + + * options.cc (General_options::parse_version): Allow -v to exit + without an error if there is nothing to link. + +2009-12-29 Ian Lance Taylor + + * configure.ac: Set the MCMODEL_MEDIUM conditional to false if + using a version of gcc before 4.1. + * configure: Rebuild. + +2009-12-28 Chris Demetriou + + * attributes.cc (Output_attributes_section_data::do_write): Use + std::vector::front rather than std::vector::data. + +2009-12-28 Ian Lance Taylor + + * symtab.h (class Symbol_table): Add enum Defined. + * resolve.cc (Symbol_table::should_override): Add defined + parameter. Change all callers. Test whether object is NULL + before calling a method on it. + (Symbol_table::report_resolve_problem): Add defined parameter. + Change all callers. + (Symbol_table::should_override_with_special): Likewise. + * symtab.cc (Symbol_table::define_in_output_data): Add defined + parameter. Change all callers. + (Symbol_table::do_define_in_output_data): Likewise. + (Symbol_table::define_in_output_segment): Likewise. + (Symbol_table::do_define_in_output_segment): Likewise. + (Symbol_table::define_as_constant): Likewise. + (Symbol_table::do_define_as_constant): Likewise. + * script.h (class Symbol_assignment): Add is_defsym parameter to + constructor; change all callers. + * script.cc (Script_options::add_symbol_assignment): Add is_defsym + parameter. Change all callers. Add is_defsym_ field. + (class Parser_closure): Add parsing_defsym parameter to + constructor; change all callers. Add parsing_defsym accessor + function. Add parsing_defsym_ field. + +2009-12-28 Ian Lance Taylor + + * gold.cc (queue_middle_tasks): Fix formatting. + * object.cc (Relobj::is_section_name_included): Likewise. + +2009-12-23 Ian Lance Taylor + + * i386.cc (Target_i386::do_calls_non_split): Recognize + -fsplit-stack prologue for a function with a static chain. + * x86_64.cc (Target_x86_64::do_calls_non_split): Recognize + -fsplit-stack prologue when using %r11. + +2009-12-21 Sriraman Tallam + + * options.cc (General_options::parse_version): Make -v continue and do + the link like GNU ld does. + +2009-12-17 Rafael Avila de Espindola + + * Makefile.am (CCFILES): Add timer.cc. + (HFILES): Add timer.h. + * configure.ac: Check for sysconf and times. + * main.cc: include timer.h. + (main): Use Timer instead of get_run_time. + * timer.cc: New. + * timer.h: New. + * workqueue.cc: include timer.h. + (Workqueue::find_and_run_task): + Report user, sys and wall time. + * Makefile.in: Regenerate. + * config.in: Regenerate. + * configure: Regenerate. + +2009-12-16 Doug Kwan + + * arm.cc (Arm_relobj::scan_sections_for_stubs): Exclude ICF-eliminated + sections. + * object.cc (Sized_relobj::do_finalize_local_symbols): Handle + relaxed input sections. + * output.cc (Output_section::find_relaxed_input_section): Change + return type to Output_relaxed_input_section pointer. Adjust code + for new type of relaxed_input_section_map_. + * output.h (Output_section::find_relaxed_input_section): Change + return type to Output_relaxed_input_section pointer. + (Output_section::Output_relaxed_input_section_by_input_section_map): + New type. + (Output_section::relaxed_input_section_map_): Change type to + Output_section::Output_relaxed_input_section_by_input_section_map. + * symtab.cc (Symbol_table::compute_final_value): Handle relaxed + input section. + +2009-12-15 Ian Lance Taylor + + * layout.cc (Layout::create_shstrtab): Only write out after input + sections if we are compressing debug sections. + +2009-12-15 Ian Lance Taylor + + * archive.cc (Archive::add_symbols): Only look up a symbol without + a version if there is, in fact, a version. + +2009-12-14 Ian Lance Taylor + + Revert -Wshadow changes, all changes from: + 2009-12-11 Doug Kwan + 2009-12-11 Nick Clifton + * configure.ac: Remove -Wshadow when setting WARN_CXXFLAGS. + +2009-12-11 Doug Kwan + + * arm.cc (Target_arm::do_finalize_sections): Fix build breakage + due to -Wshadow. + * attributes.cc (Object_attribute::size): Ditto. + (Attributes_section_data::size): Ditto. + (Attributes_section_data::Attributes_section_data): Ditto. + (Output_attributes_section_data::do_write): Ditto. + * attributes.h (Object_attribute::set_type): Ditto. + * testsuite/tls_test_main.cc (safe_lock, safe_unlock): Ditto. + +2009-12-11 Nick Clifton + + * archive.cc: Fix shadowed variable warnings. + * arm.cc: Likewise. + * compressed_output.cc: Likewise. + * compressed_output.h: Likewise. + * configure: Likewise. + * dwarf_reader.cc: Likewise. + * dynobj.cc: Likewise. + * dynobj.h: Likewise. + * ehframe.cc: Likewise. + * ehframe.h: Likewise. + * errors.cc: Likewise. + * expression.cc: Likewise. + * fileread.cc: Likewise. + * fileread.h: Likewise. + * freebsd.h: Likewise. + * i386.cc: Likewise. + * icf.cc: Likewise. + * incremental.h: Likewise. + * layout.cc: Likewise. + * layout.h: Likewise. + * mapfile.cc: Likewise. + * merge.cc: Likewise. + * merge.h: Likewise. + * object.cc: Likewise. + * object.h: Likewise. + * options.h: Likewise. + * output.cc: Likewise. + * output.h: Likewise. + * parameters.cc: Likewise. + * plugin.cc: Likewise. + * powerpc.cc: Likewise. + * reduced_debug_output.cc: Likewise. + * reduced_debug_output.h: Likewise. + * reloc.cc: Likewise. + * reloc.h: Likewise. + * resolve.cc: Likewise. + * script-sections.cc: Likewise. + * script.cc: Likewise. + * script.h: Likewise. + * sparc.cc: Likewise. + * symtab.cc: Likewise. + * symtab.h: Likewise. + * target-select.cc: Likewise. + * target-select.h: Likewise. + * token.h: Likewise. + * workqueue.cc: Likewise. + * workqueue.h: Likewise. + * x86_64.cc: Likewise. + +2009-12-10 Doug Kwan + + * arm.cc (attributes.h): New include. + (Arm_relobj::Arm_relobj): Initialize attributes_section_data_. + (Arm_relobj::~Arm_relobj): Delete object pointed by + attributes_section_data_. + (Arm_relobj::attributes_section_data): New method definition. + (Arm_relobj::attributes_section_data_): New data member declaration. + (Arm_dynobj::Arm_dynobj): Initialize attributes_section_data_. + (Arm_dynobj::~Arm_dynobj): Delete object pointed by + attributes_section_data_. + (Arm_dynobj::attributes_section_data): New method definition. + (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::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, + Target_arm::get_secondary_compatible_arch, + Target_arm::set_secondary_compatible_arch + Target_arm::tag_cpu_arch_combine, Target_arm::aeabi_enum_name, + Target_arm::tag_cpu_name_value, Target_arm::merge_object_attributes): + New method declarations. + (Target_arm::get_aeabi_object_attribute): New method definition. + (Target_arm::attributes_section_data_): New data member declaration. + (read_arm_attributes_section): New template definition. + (Arm_relobj::do_read_symbols): Read attributes section if it exists. + (Arm_dynobj::do_read_symbols): Ditto. + (Target_arm::do_finalize_sections): Merge attributes sections from + input. Check for BLX use after attributes section merging. + Fix __exidx_start and __exidx_end visibility. Create an + .ARM.attributes section if necessary. + (Target_arm::get_secondary_compatible_arch, + Target_arm::set_secondary_compatible_arch, + Target_arm::tag_cpu_arch_combine, Target_arm::aeabi_enum_name, + Target_arm::tag_cpu_name_value, Target_arm::merge_object_attributes, + Target_arm::do_attribute_arg_type, Target_arm::do_attributes_order): + New method definitions. + +2009-12-09 Ian Lance Taylor + + * plugin.cc (Plugin::load): Don't cast from void* to a function + pointer. + +2009-12-09 Ian Lance Taylor + + * dynobj.cc (Sized_dynobj::do_read_symbols): Clear version + information fields. + +2009-12-09 H.J. Lu + + * testsuite/Makefile.am (two_file_shared_1_pic_2_test_DEPENDENCIES): + Replace two_file_shared_1.so with two_file_shared_2.so. + * testsuite/Makefile.in: Regenerated. + +2009-12-08 Doug Kwan + + * Makefile.am (CCFILES): Add attributes.cc and int_encoding.cc. + (HFILES): Add attributes.h and int_encoding.h. + * Makefile.in: Regenerate. + * dwarf_reader.cc (read_unsigned_LEB_128, read_signed_LEB_128): Move + function definitions to int_encoding.cc + * dwarf_reader.h (read_unsigned_LEB_128, read_signed_LEB_128): Move + prototypes to int_encoding.h + * reduced_debug_output.cc (int_encoding.h): New include. + (write_unsigned_LEB_128, get_length_as_unsigned_LEB_128): Move + function definitions to int_encoding.cc + (insert_into_vector, read_from_pointer): Move template definitions to + int_encoding.h + * attributes.cc: New file. + * attributes.h: New file. + * int_encoding.cc: New file. + * int_encoding.h: New file. + +2009-12-07 Rafael Avila de Espindola + + PR gold/11055 + * incremental-dump.cc (dump_incremental_inputs): New. + (main): Use dump_incremental_inputs. + +2009-12-07 H.J. Lu + + PR gold/10893 + * i386.cc (Target_i386::Scan::globa): Use is_func instead of + checking elfcpp::STT_FUNC. + (Target_i386::Relocate::relocate): Likewise. + * x86_64.cc (Target_x86_64::Scan::global): Likewise. + + * symtab.cc (Symbol_table::sized_write_symbol): Turn IFUNC + symbols from shared libraries into normal FUNC symbols. + + * symtab.h (Symbol): Add is_func and use it. + +2009-12-05 Doug Kwan + + * arm.cc (Target_arm::arm_info): Initialize new fields + attributes_section and attributes_vendor. + * i386.cc (Target_i386::i386_info): Same. + * object.cc (Sized_relobj::do_layout): Skip attribute section. + * gold/powerpc.cc (Target_powerpc::powerpc_info): Initialize new + fields attributes_section and attributes_vendor. + * sparc.cc (Target_sparc::sparc_info): Same. + * target.h (Target::attributes_section, Target::attributes_vendor, + Target::is_attributes_section, Target::attribute_arg_type, + Target::attributes_order): New method definitions. + (Target::Target_info::attributes_section, + Target::Target_info::attributes_vendor): New fields. + (Target::do_attribute_arg_type, Target::do_attributes_order): New + virtual method definitions. + * x86_64.cc (Target_x86_64::x86_64_info): Initialize new fields + attributes_section and attributes_vendor. + * testsuite/testfile.cc (Target_test::test_target_info): Same. + +2009-12-05 Doug Kwan + + * arm.cc: Update comments about interworking and stub generation. + (Target_arm::Relocate::reloc_is_non_pic): Update list of relocations + considered as non-PIC. + (Arm_relocate_functions::base_abs): Fix formatting. + (Arm_relocate_functions::got_prel): Fix comment. Change interface + of function to use GOT entry address instead of offset. + (Target_arm::Scan::global): Issue an error if a symbol would need a + PLT does not get one because it is untyped. Remove code to create + dynamic symbols for relative branches. + (Target_arm::Relocate::relocate: Use 0 instead of false since function + takes unsigned integer instead of boolean. + +2009-12-05 H.J. Lu + + * testsuite/Makefile.am (constructor_test_LDADD): New. Empty. + (two_file_test_LDADD): Likewise. + (common_test_1_LDADD): Likewise. + (exception_test_LDADD) Likewise. + (weak_test_LDADD): Likewise. + (many_sections_test_LDADD): Likewise. + (initpri1_LDADD): Likewise. + (script_test_1_LDADD): Likewise. + (script_test_2_LDADD): Likewise. + (justsyms_LDADD): Likewise. + (binary_test_LDADD): Likewise. + (large_LDADD): Likewise. + * testsuite/Makefile.in: Regenerated. + +2009-12-04 H.J. Lu + + * resolve.cc (symbol_to_bits): Treat STB_GNU_UNIQUE as STB_GLOBAL. + (Symbol_table::override_with_special): Likewise. + (Symbol_table::add_from_object): Likewise. + +2009-12-04 Rafael Avila de Espindola + + * incremental.cc (Incremental_inputs::sized_create_inputs_section_data): + Don't set the data_offset twice. + +2009-12-04 Rafael Avila de Espindola + + * testsuite/Makefile.in: Regenerate. + +2009-12-03 Doug Kwan + + * arm.cc: Remove comment about missing .ARM.exidx section symbols. + (Target_arm::do_finalize_sections): Add parameter for symbol table + pointer. Add __exidx_start and __exidx_end symbols as appropriate. + * i386.cc (Target_i386::do_finalize_sections): Add an additional + parameter for symbol table pointer. + * layout.cc (Layout::finalize): Call Target::finalize_sections with + an additional parameter for a pointer to symbol table. + * powerpc.cc (Target_powerpc::do_finalize_sections): Add an additional + parameter for a symbol table pointer. + * sparc.cc (Target_sparc::do_finalize_sections): Ditto. + * target.h (Target::finalize_sections, Target::do_finalize_sections): + Ditto. + * x86_64.cc (Target_x86_64::do_finalize_sections): Add an additional + parameter for a symbol table pointer. + +2009-12-03 Rafael Avila de Espindola + + * incremental.cc (Incremental_inputs_header) + (Incremental_inputs_header_write, Incremental_inputs_entry) + (Incremental_inputs_entry_write): Move ... + * incremental.h (Incremental_inputs_header) + (Incremental_inputs_header_write, Incremental_inputs_entry) + (Incremental_inputs_entry_write): here. + +2009-12-02 Rafael Avila de Espindola + + * incremental.cc (make_sized_incremental_binary): Set the target. + Error if it is incompatible. + * output.h (Output_file): Add filename method. + +2009-12-02 Rafael Avila de Espindola + + * incremental.cc (Incremental_inputs_entry): Remove unused argument + from the get_* methods. + +2009-12-02 Rafael Avila de Espindola + + * incremental-dump.cc (main): Check that the offeset of a script is 0. + * incremental.cc (Incremental_inputs::sized_create_inputs_section_data): + Write 0 for the data_offset of scripts. + +2009-12-02 Rafael Avila de Espindola + + * testsuite/Makefile.am: Add the incremental_test.sh test. + * testsuite/incremental_test.sh: New. + * testsuite/incremental_test_1.c: New. + * testsuite/incremental_test_2.c: New. + +2009-12-01 Rafael Avila de Espindola + + * incremental-dump.cc (main): Fix typos. + +2009-11-27 Rafael Avila de Espindola + + PR gold/11025 + * incremental-dump.cc (main): Use llu to print 64 bit values. + +2009-11-26 Per Øyvind Karlsen + H.J. Lu + + * Makefile.am (incremental_dump_DEPENDENCIES): Add $(THREADSLIB) + $(LIBDL). + (incremental_dump_LDADD): Likewise. + * Makefile.in: Regenerated. + +2009-11-25 Doug Kwan + + Revert: + + 2009-11-25 Doug Kwan + + * arm.cc (Target_arm::Target_arm): Move method definition + outside of class definition. Add code to handle + --target1-rel, --target1-abs and --target2= options. + (Target_arm::get_reloc_reloc_type): Change method to be + non-static and const. + (Target_arm::target1_is_rel_, Target_arm::target2_reloc_): + New data member declaration. + (Target_arm::Scan::local, Target_arm::Scan::global, + Target_arm::Relocate::relocate, + Target_arm::Relocatable_size_for_reloc::get_size_for_reloc): + Adjust call to Target_arm::get_real_reloc_type. + (Target_arm::get_real_reloc_type): Use command line options + to determine real types of R_ARM_TARGET1 and R_ARM_TARGET2. + * options.h (--target1-rel, --target1-abs, --target2): New + ARM-only options. + +2009-11-25 Doug Kwan + + * arm.cc (Target_arm::Target_arm): Move method definition outside of + class definition. Add code to handle --target1-rel, --target1-abs + and --target2= options. + (Target_arm::get_reloc_reloc_type): Change method to be non-static + and const. + (Target_arm::target1_is_rel_, Target_arm::target2_reloc_): New data + member declaration. + (Target_arm::Scan::local, Target_arm::Scan::global, + Target_arm::Relocate::relocate, + Target_arm::Relocatable_size_for_reloc::get_size_for_reloc): Adjust + call to Target_arm::get_real_reloc_type. + (Target_arm::get_real_reloc_type): Use command line options to + determine real types of R_ARM_TARGET1 and R_ARM_TARGET2. + * options.h (--target1-rel, --target1-abs, --target2): New ARM-only + options. + +2009-11-25 Doug Kwan + + * arm.cc (Target_arm::may_use_thumb2_nop): New method definition. + (Arm_relocate_functions::thumb_branch_common): New metod declaration. + (Arm_relocate_functions::abs12, Arm_relocate_functions::abs16): Fix + formatting. + (Arm_relocate_functions::thm_call): Replace body with a call to + Arm_relocate_functions::thumb_branch_common. + (Arm_relocate_functions::thm_jump24, + Arm_relocate_functions::thm_xpc22): New method definitions. + (Arm_relocate_functions::thumb_branch_common): New method definition. + (Reloc_stub::stbu_type_for_reloc): Fix incorrect uses of bit-wise-or + operator. + (Target_arm::Relocate::relocate): Adjust call to thm_call. + Add code to handle R_ARM_THM_XPC22 and R_ARM_THM_JUMP24. + +2009-11-24 Rafael Avila de Espindola + + * Makefile.am: Build incremental-dump + * Makefile.in: Regenerate. + * incremental-dump.cc: New. + * incremental.cc (Incremental_inputs_header_data, + Incremental_inputs_entry_data): Move to incremental.h + * incremental.h: (Incremental_inputs_header_data, + Incremental_inputs_entry_data): Move from incremental.cc + +2009-11-24 Rafael Avila de Espindola + + * incremental.cc (Incremental_inputs_header, + Incremental_inputs_header_write, Incremental_inputs_entry, + Incremental_inputs_entry_write): Add a typedef with the data type. + +2009-11-24 Rafael Avila de Espindola + + * incremental.cc (Incremental_inputs_header, + Incremental_inputs_header_write, Incremental_inputs_entry, + Incremental_inputs_entry_write): Update comment about which + type has the filed descriptions. + +2009-11-15 Doug Kwan + + * arm.cc (Target_arm::may_use_arm_nop): New method definition. + (Arm_relocate_functions::arm_branch_common): Change method defintion + in class definition to a method declaration and update list of formal + parameters. + (Arm_relocate_functions::plt32, Arm_relocate_functions::call, + Arm_relocation_functions::jump24): Adjust call to + Arm_relocate_functions::arm_branch_common. Update list of formal + parameters. + (Arm_relocate_functions::xpc25): New method definition. + (Arm_relocate_functions::arm_branch_common): Move method defintion + out from class definition. Use stubs for mode-switching and extending + branch ranges. + (Target_arm::Relocate::relocate): Handle weakly-undefined symbols + specially. Change code to enable use of stubs in ARM branches. + +2009-11-10 Doug Kwan + + * arm.cc (Arm_relobj::do_relocate_sections): Remove options parameter + in method declaration. + (Target_arm::relocate_stub): New method declaration. + (Target_arm::default_target): Change to return a pointer instead of + a const reference. + (Reloc_stub::stub_type_for_reloc): Adjust for the change in + Target_arm::default_target. + (Arm_Relobj::do_relocate_sections): Remove options paramater in + method definition. + (Target_arm::relocate_section): Adjust view. + (Target_arm::relocate_stub): New method definition. + +2009-11-10 Doug Kwan + + * i386.cc (Target_i386::do_calls_non_split): Add a cast to avoid + a format warning. + * incremental.cc (open_incremental_binary): Initialized local + variables to avoid warnings. + * object.cc (make_elf_object): Ditto. + * x86_64.cc (Target_x86_64::do_calls_non_split): Add a cast to avoid + a format warning. + +009-11-09 H.J. Lu + + PR gold/10930 + * testsuite/plugin_test.c: Include "config.h". + +2009-11-09 Doug Kwan + + * arm.cc (Target_arm::fake_relnum_for_stubs): New constant. + (arm_symbol_value): Remove. + (Arm_relocate_functions::arm_branch_common, + Arm_relocate_functions::abs8, Arm_relocate_functions::thm_abs5, + Arm_relocate_functions::abs12, Arm_relocate_functions::abs16, + Arm_relocate_functions::abs32, Arm_relocate_functions::rel32, + Arm_relocate_functions::thm_call, Arm_relocate_functions::plt32, + Arm_relocate_functions::call, Arm_relocate_functions::jump24, + Arm_relocate_functions::prel31, Arm_relocate_functions::mov_abs_nc, + Arm_relocate_functions::movt_abs, Arm_relocate_functions::movw_abs_nc, + Arm_relocate_functions::thm_mobw_abs_nc, + Arm_relocate_functions::thm_mov_abs, + Arm_relocate_functions::movw_prel_nc, + Arm_relocate_functions::thm_movt_abs, + Arm_relocate_functions::movt_prel, + Arm_relocate_functions::thm_movw_prel_nc, + Arm_relocate_functions::thm_movt_prel): Adjust callers of the above. + (Target_arm::Relocate::relocate): Only decompose address into two + parts if relocation type uses the thumb-bit and pass the actual + bit instead of a flag indicating that the thumb-bit is used. Adjust + calls to methods in Arm_relocate_functions for this change. + +2009-11-08 Ian Lance Taylor + + PR 10925 + * reloc.cc: Instantiate + Sized_relobj::initialize_input_to_output_maps and + Sized_relobj:free_input_to_output_maps. + +2009-11-06 Ian Lance Taylor + + PR 10876 + * defstd.cc (in_segment): Set only_if_ref true for "end". + +2009-11-06 Doug Kwan + + * arm.cc (class Reloc_stub): Correct a comment. + (Target_arm::Target_arm): Initialize arm_input_section_map_. + (Target_arm::scan_section_for_stubs): New method declaration. + (Target_arm::do_make_elf_object, Target_arm::do_make_output_section): + Change methods from private to protected. + (Target_arm::do_may_relax): New method definition. + (Target_arm::do_relax, Target_arm::group_sections, + Target_arm::scan_reloc_for_stub, + Target_arm::scan_reloc_section_for_stubs): New method declarations. + (Target_arm::arm_input_section_map_): New data member declaration. + (Target_arm::scan_reloc_for_stub, + Target_arm::scan_reloc_section_for_stubs, + Target_arm::scan_section_for_stubs, Target_arm::group_sections, + Target_arm::do_relax): New method definitions. + +2009-11-06 Mikolaj Zalewski + + * configure.ac: Check for (struct stat)::st_mtim + * fileread.cc (File_read::get_mtime): Use st_mtim if available. + * config.in: Regenerate. + * configure: Regenerate. + +2009-11-05 Ian Lance Taylor + + PR 10910 + * output.cc (Output_segment::add_output_section): Add missing + return statement. + +2009-11-04 Ian Lance Taylor + + PR 10880 + * object.h (class Object): Add is_needed and set_is_needed + methods. Add is_needed_ field. Make bool fields into bitfields. + * symtab.cc (Symbol_table::set_dynsym_indexes): If a symbol is + defined in a dynamic object and referenced by a regular object, + set is_needed for the dynamic object. + * layout.cc (Layout::finish_dynamic_section): Don't add DT_NEEDED + if the file is marked with as_needed and it is not needed. + +2009-11-04 Ian Lance Taylor + + PR 10887 + * arm.cc (Target_arm::do_finalize_sections): Don't add dynamic + tags if data is discarded by linker script. + * i386.cc (Target_i386::do_finalize_sections): Likewise. + * powerpc.cc (Target_powerpc::do_finalize_sections): Likewise. + * sparc.cc (Target_sparc::do_finalize_sections): Likewise. + * x86_64.cc (Target_x86_64::do_finalize_sections): Likewise. + +2009-11-04 Ian Lance Taylor + + * layout.cc (Layout::get_output_section): Add is_interp and + is_dynamic_linker_section parameters. Change all callers. + (Layout::choose_output_section): Likewise. + (Layout::make_output_section): Likewise. + (Layout::add_output_section_data): Add is_dynamic_linker_section + parameter. Change all callers. + * layout.h (class Layout): Update declarations. + * output.h (class Output_section): Add is_interp, set_is_interp, + is_dynamic_linker_section, set_is_dynamic_linker_section methods. + Add is_interp_, is_dynamic_linker_section_ fields. Change + generate_code_fills_at_write_ to a bitfield. + * output.cc (Output_section::Output_sections): Initialize new + fields. + (Output_segment::add_output_section): Add do_sort parameter. + Change all callers. + +2009-11-03 Ian Lance Taylor + + PR 10860 + * options.h (class General_options): Add --warn-common. + * resolve.cc (Symbol_table::resolve): Handle --warn-common when + merging two common symbols. + (Symbol_table::should_override): Handle --warn-common when merging + a common symbol with a defined symbol. Use report_resolve_problem + for multiple definitions. + (Symbol_table::report_resolve_problem): New function. + * symtab.h (class Symbol_table): Declare report_resolve_problem. + +2009-11-03 Doug Kwan + + * arm.cc (Target_arm::Target_arm): Initialize stub_tables_ and + stub_factory_. + (Target_arm::stub_factory): New method definition. + (Target_arm::new_arm_input_section, + Target_arm::find_arm_input_section, Target_arm::new_stub_table, + Target_arm::reloc_uses_thumb_bit): New method declarations. + (Target_arm::Stub_table_list, Target_arm::Arm_input_section_map): + New type definitions. + (Target_arm::stub_tables_, Target_arm::stub_factory_): New data + member declarations. + (Target_arm::reloc_uses_thumb_bit, Target_arm::new_arm_input_section, + Target_arm::find_arm_input_section, Target_arm::new_stub_table): + New method definitions. + +2009-11-03 Ian Lance Taylor + + * options.h (class General_options): Add --warn_constructors. + +2009-11-03 Ian Lance Taylor + + PR 10893 + * defstd.cc (in_section): Add entries for __rel_iplt_start, + __rel_iplt_end, __rela_iplt_start, __rela_iplt_end, and __stack. + +2009-11-03 Ian Lance Taylor + + PR 10895 + * po/Make-in ($(srcdir)/$(PACKAGE).pot): Pass -C and + --msgid-bugs-address. + (install-pdf): New target. + (install-data_yes): Look up one directory to find mkinstalldirs. + +2009-11-03 H.J. Lu + + * po/Make-in (.po.gmo): Don't generate .gmo files in source + tree. + +2009-10-30 Doug Kwan + + * arm.cc (Stub_addend_reader): Fix bug in previouls check-in. + +2009-10-30 Doug Kwan + + * arm.cc (Stub_addend_reader): New struct template definition + and partial specializations. + (Stub_addend_reader::operator()): New method definition for a + partially specialized template. + +2009-10-30 Doug Kwan + + * arm.cc (Arm_relobj::processor_specific_flags): New method + definition. + (Arm_relobj::do_read_symbols): New method declaration. + (Arm_relobj::processor_specific_flags_): New data member declaration. + (Arm_dynobj): New class definition. + (Target_arm::do_finalize_sections): Add input_objects parameter. + (Target_arm::do_adjust_elf_header): New method declaration. + (Target_arm::are_eabi_versions_compatible, + (Target_arm::merge_processor_specific_flags): New method declaration. + (Target_arm::do_make_elf_object): New overloaded method definitions + and declaration. + (Arm_relobj::do_read_symbols): New method definition. + (Arm_dynobj::do_read_symbols): Ditto. + (Target_arm::do_finalize_sections): Add input_objects parameters. + Merge processor-specific flags from all input objects. + (Target_arm::are_eabi_versions_compatible, + Target_arm::merge_processor_specific_flags, + Target_arm::do_adjust_elf_header, Target_arm::do_make_elf_object): + New method definitions. + * i386.cc (Target_i386::do_finalize_sections): Add unnamed + Input_objects pointer type parameter. + * layout.cc (Layout::finalize): Pass input objects to target's. + finalize_sections function. + * output.cc (Output_file_header::do_sized_write): Set ELF file + header's processor-specific flags. + * powerpc.cc (Target_powerpc::do_finalize_sections): Add unnamed + Input_objects pointer type parameter. + * sparc.cc (Target_sparc::do_finalize_sections): Same. + * target.h (Input_objects): New forward class declaration. + (Target::processor_specific_flags, + Target::are_processor_specific_flags_sect): New method definitions. + (Target::finalize_sections): Add input_objects parameter. + (Target::Target): Initialize processor_specific_flags_ and + are_processor_specific_flags_set_. + (Target::do_finalize_sections): Add unnamed Input_objects pointer type + parameter. + (Target::set_processor_specific_flags): New method definition. + (Target::processor_specific_flags_, + Target::are_processor_specific_flags_set_): New data member + declarations. + * x86_64.cc (Target_x86_64::do_finalize_sections): Add unnamed + Input_objects pointer type parameter. + +2009-10-30 Doug Kwan + + * arm.cc: Use Arm_address instead of elfcpp::Elf_types<32>::Elf_Addr. + +2009-10-28 Ian Lance Taylor + + * object.h (class Relobj): Drop options parameter from + gc_process_relocs, scan_relocs, relocate, do_gc_process_relocs, + do_scan_relocs, do_relocate. Change all callers. + (class Sized_relobj): Drop options parameters from + do_gc_process_relocs, do_scan_relocs, do_relocate, + do_relocate_sections, relocate_sections, emit_relocs_scan, + emit_relocs_scan_reltype. Change all callers. + (struct Relocate_info): Remove options field and all references to + it. + * reloc.h (class Read_relocs): Remove options constructor + parameter and options_ field. Change all callers. + (class Gc_process_relocs, class Scan_relocs): Likewise. + (class Relocate_task): Likewise. + * target-reloc.h (scan_relocs): Remove options parameter. Change + all callers. + (scan_relocatable_relocs): Likewise. + * target.h (class Sized_target): Remove options parameter from + gc_process_relocs, scan_relocs, scan_relocatable_relocs. Change + all callers. + * gc.h (gc_process_relocs): Remove options parameter. Change all + callers. + * arm.cc: Update functions to remove options parameters. + * i386.cc: Likewise. + * powerpc.cc: Likewise. + * sparc.cc: Likewise. + * x86_64.cc: Likewise. + * testsuite/testfile.cc: Likewise. + +2009-10-28 Doug Kwan + + * arm.cc (Arm_relobj): New class definition. + (Arm_relobj::scan_sections_for_stubs, + Arm_relobj::do_count_local_symbols, Arm_relobj::do_relocate_sections): + New method definitions. + +2009-10-28 Cary Coutant + + * plugin.h (Plugin::Plugin): Initialize cleanup_done_. + (Plugin::cleanup_done_): New member. + (Plugin_manager::Plugin_manager): Remove cleanup_done_. + (Plugin_manager::cleanup_done_): Remove. + (Plugin_manager::add_input_file): Edit error message. + * plugin.cc (Plugin::cleanup): Test and set cleanup_done_. + (Plugin_manager::cleanup): Remove use of cleanup_done_. + +2009-10-27 Mikolaj Zalewski + + * fileread.cc: (File_read::View::~View): Use the new + data_ownership_ filed. + (File_read::~File_read): Dispose the new whole_file_view_. + (File_read::open): Mmap the whole file if needed. + (File_read::open): Use whole_file_view_ instead of contents_. + (File_read::find_view): Use whole_file_view_ if applicable. + (File_read::do_read): Use whole_file_view_ instead of contents_. + (File_read::make_view): Use whole_file_view_ instead of contents_, + update File_read::View::View call. + (File_read::find_or_make_view): Update File_read::View::View + call. + * fileread.h: (File_read::File_read): Initialize whole_file_view_, + remove contents_ + (File_read::View::Data_ownership): New enum. + (File_read::View::View): Replace bool mapped_ with Data_ownership + argument. + (File_read::View::mapped_): Remove (replaced by data_ownership_). + (File_read::View::data_ownership_): New field. + (File_read::contents_): Remove (replaced by whole_file_view_). + (File_read::whole_file_view_): New field. + * options.h (class General_options): Add --keep-files-mapped. + +2009-10-27 Cary Coutant + + * symtab.cc (add_from_pluginobj): Pass correct value for is_ordinary. + * testsuite/Makefile.am (plugin_test_5): New test case. + * testsuite/Makefile.in: Regenerate. + +2009-10-25 Doug Kwan + + * object.h (Sized_relobj::View_size, Sized_relobj::Views): Change + from private to protected to allow access by child class. + (Sized_relobj::do_relocate_sections): New method declaration. + (Sized_relobj::relocate_sections): Virtualize. + * reloc.cc (Sized_relobj::do_relocate_sections): Rename from + Sized_relobj::relocate_sections. Instantiate template explicitly + for different target sizes and endianity. + +2009-10-24 Doug Kwan + + * arm.cc (Arm_output_section, Arm_relobj): Forward class declarations. + (Arm_input_section::as_arm_input_section): New method. + (Arm_output_section): New class definition. + (Arm_output_section::create_stub_group, + Arm_output_section::group_sections): New method definitions. + +2009-10-22 Doug Kwan + + * arm.cc (Arm_input_section): New class definition. + (Arm_input_section::init, Arm_input_section:do_write, + Arm_input_section::set_final_data_size, + Arm_input_section::do_reset_address_and_file_offset): New method + definitions. + +2009-10-21 Doug Kwan + + * arm.cc (Stub_table, Arm_input_section): New forward class + declarations. + (Stub_table): New class defintion. + (Stub_table::add_reloc_stub, Stub_table::relocate_stubs + Stub_table::do_reset_address_and_file_offset, Stub_table::do_write): + New method definition. + +2009-10-21 Doug Kwan + + * arm.cc: Update copyright comments. + (Target_arm): New forward class template declaration. + (Arm_address): New type. + (ARM_MAX_FWD_BRANCH_OFFSET, ARM_MAX_BWD_BRANCH_OFFSET, + THM_MAX_FWD_BRANCH_OFFSET, THM_MAX_BWD_BRANCH_OFFSET, + THM2_MAX_FWD_BRANCH_OFFSET, THM2_MAX_BWD_BRANCH_OFFSET): New + constants. + (Insn_template): Same. + (DEF_STUBS): New macro. + (Stub_type): New enum type. + (Stub_template): New class definition. + (Stub): Same. + (Reloc_stub): Same. + (Stub_factory): Same. + (Target_arm::Target_arm): Initialize may_use_blx_ and + should_force_pic_veneer_. + (Target_arm::may_use_blx, Target_arm::set_may_use_blx, + Target_arm::should_force_pic_veneer, + Target_arm::set_should_force_pic_veneer, Target_arm::using_thumb2, + Target_arm::using_thumb_only, Target_arm:;default_target): New + method defintions. + (Target_arm::may_use_blx_, Target_arm::should_force_pic_veneer_): + New data member declarations. + (Insn_template::size, Insn_template::alignment): New method defintions. + (Stub_template::Stub_template): New method definition. + (Reloc_stub::Key::name, Reloc_stub::stub_type_for_reloc, + Reloc_stub::do_fixed_endian_write, Reloc_stub::do_write): Same. + (Stub_factory::Stub_factory): New method definition. + * gold.h (string_hash): New template. + * output.h (Input_section_specifier::hash_value): Use + gold::string_hash. + (Input_section_specifier::string_hash): Remove. + * stringpool.cc (Stringpool_template::string_hash): Use + gold::string_hash. + +2009-10-20 Doug Kwan + + * object.cc (Sized_relobj::do_finalize_local_symbols): Handle section + symbols of relaxed input sections. + * output.h (Output_section::find_relaxed_input_section): Make + method public. + +2009-10-16 Doug Kwan + + * dynobj.cc (Versions::Versions): Initialize version_script_. + Only insert base version symbol definition for a shared object + if version script defines any version versions. + (Versions::define_base_version): New method definition. + (Versions::add_def): Check that base version is not needed. + (Versions::add_need): Define base version lazily. + * dynobj.h (Versions::define_base_version): New method declaration. + (Versions::needs_base_version_): New data member declaration. + * testsuite/Makefile.am (check_SCRIPTS): Add no_version_test.sh + (check_DATA): Add no_version_test.stdout. + (libno_version_test.so, no_version_test.o no_version_test.stdout): + New make rules. + * testsuite/Makefile.in: Regenerate. + * testsuite/no_version_test.c: New file. + * testsuite/no_version_test.sh: Ditto. + +2009-10-16 Doug Kwan + + * expression.cc (class Segment_start_expression): New class definition. + (Segment_start_expression::value): New method definition. + (script_exp_function_segment_start): Return a new + Segment_start_expression. + * gold/script-c.h (script_saw_segment_start_expression): New function + prototype. + * script-sections.cc (Script_sections::Script_sections): Initialize + SAW_SEGMENT_START_EXPRESSION_ to false. + (Script_sections::set_section_addresses): Use -Ttext, -Tdata + and -Tbbs options to specify section addresses if given in + command line and no SEGMENT_START expression is seen in a script. + * script-sections.h (Script_sections::saw_segment_start_expression, + Script_sections::set_saw_segment_start_expression): New method + definition. + (Script_sections::saw_segment_start_expression_): New data member + declaration. + * script.cc (script_saw_segment_start_expression): New function. + * yyscript.y (SEGMENT_START): Call script_saw_segment_start_expression. + * testsuite/Makefile.am (check_SCRIPTS): Add script_test_6.sh, + script_test_7.sh and script_test_8.sh. + (check_DATA): Add script_test_6.stdout, script_test_7.stdout and + script_test_8.stdout. + (MOSTLYCLEANFILES): Add script_test_6, script_test_7 and script_test_8. + (script_test_6, script_test_6.stdout, script_test_7, + script_test_7.stdout, script_test_8, script_test_8.stdout): New rules. + * Makefile.in: Regenerate. + * testsuite/script_test_6.sh: New file. + * testsuite/script_test_6.t: Same. + * testsuite/script_test_7.sh: Same. + * testsuite/script_test_7.t: Same. + * testsuite/script_test_8.sh: Same. + +2009-10-16 Doug Kwan + + * output.cc (Output_segment::set_section_list_address): Cast + expressions to unsigned long long type to avoid format warnings. + +2009-10-15 Ian Lance Taylor + + * script.cc (Script_options::add_symbol_assignment): Always add a + dot assignment to script_sections_. + * script-sections.cc (Script_sections::add_dot_assignment): + Initialize if necessary. + + * layout.cc (Layout::relaxation_loop_body): Don't crash if we see + program headers with no load segment if there is a linker script. + + * layout.cc (Layout::set_segment_offsets): Align the file offset + to the segment aligment for -N or -n with no load segment. + * output.cc (Output_segment::add_output_section): Don't crash if + the first section is a TLS section. + (Output_segment::set_section_list_addresses): Print an error + message if the address moves backward in a linker script. + * script-sections.cc + (Output_section_element_input::set_section_addresses): Don't + increase *dot_value for a SHF_TLS/SHT_NOBITS section. + (Orphan_output_section::set_section_addresses): Likewise. + +2009-10-15 Doug Kwan + + * layout.cc (Layout::finish_dynamic_section): Generate tags + DT_FINI_ARRAY, DT_FINI_ARRAYSZ, DT_INIT_ARRAY, DT_INIT_ARRAYSZ, + DT_PREINIT_ARRAY, DT_PREINIT_ARRAYSZ as needed. If -Bsymbolic is + used, add DT_SYMBOLIC and set DF_SYMBOLIC in DT_FLAGS. + +2009-10-14 Ian Lance Taylor + + * object.h (class Relocate_info): Add reloc_shdr and data_shdr + fields. + * object.cc (Sized_relobj::relocate_sections): Set reloc_shdr and + data_shdr fields of relinfo. + * i386.cc (class Target_i386::Relocate): Remove ldo_addrs_ field. + (Target_i386::Relocate::relocate_tls): Don't call fix_up_ldo. For + R_386_TLS_LDO_32, adjust based on section flags. + (Target_i386::Relocate::fix_up_ldo): Remove. + +2009-10-13 Ian Lance Taylor + + Add support for -pie. + * options.h (class General_options): Add -pie and + --pic-executable. + (General_options::output_is_position_independent): Test -pie. + (General_options::output_is_executable): Return true if not shared + and not relocatable. + (General_options::output_is_pie): Remove. + * options.cc (General_options::finalize): Reject incompatible uses + of -pie. + * gold.cc (queue_middle_tasks): A -pie link is not static. + * symtab.h (Symbol::needs_plt_entry): Return false if -pie. + * symtab.cc (Symbol::final_value_is_known): Return false if + output_is_position_independent. + * layout.cc (Layout::set_segment_offsets): Start at address 0 if + output_is_position_independent. + * output.cc (Output_file_header::do_sized_write): Use ET_DYN if + output_is_position_independent. + * i386.cc (Output_data_plt_i386::do_write): Use the PIC PLT if + output_is_position_independent. + * testsuite/Makefile.am (check_PROGRAMS): Add basic_pie_test and + two_file_pie_test. + (basic_pie_test.o, basic_pie_test): New targets. + (two_file_test_1_pie.o, two_file_test_1b_pie.o): New targets. + (two_file_test_2_pie.o, two_file_test_main_pie.o): New targets. + (two_file_pie_test): New target. + * testsuite/Makefile.in: Rebuild. + * README: Remove note saying that -pie is not supported. + +2009-10-13 Bernhard Reutner-Fischer + + * options.h (class General_options): Add -init and -fini. + * layout.cc (Layout::finish_dynamic_section): Emit + given init and fini functions. + +2009-10-13 Sriraman Tallam + + * gc.h (gc_process_relocs): Check if icf is enabled using new + function. + * gold.cc (queue_initial_tasks): Likewise. + (queue_middle_tasks): Likewise. + * object.cc (do_layout): Likewise. + * symtab.cc (is_section_folded): Likewise. + * main.cc (main): Likewise. + * reloc.cc (Read_relocs::run): Likewise. + (Sized_relobj::do_scan_relocs): Likewise. + * icf.cc (is_function_ctor_or_dtor): New function. + (Icf::find_identical_sections): Check if function is ctor or dtor when + safe icf is chosen. + * options.h (General_options::icf): Change option to be an enum. + (Icf_status): New enum. + (icf_enabled): New method. + (icf_safe_folding): New method. + (set_icf_status): New method. + (icf_status_): New variable. + * (options.cc) (General_options::finalize): Set icf_status_. + * testsuite/Makefile.am: Add commands to build icf_safe_test. Modify + icf_test and icf_keep_unique_test to use the --icf enum flag. + * testsuite/icf_safe_test.sh: New file. + * testsuite/icf_safe_test.cc: New file. + +2009-10-12 Sriraman Tallam + + * symtab.h: Check for GOLD_SYMTAB_H before header includes. Remove + includes to gc.h and icf.h. + * arm.cc: Include gc.h. + * gold.cc: Likewise. + * i386.cc: Likewise. + * powerpc.cc: Likewise. + * sparc.cc: Likewise. + * x86_64.cc: Likewise. + * gc.h: Include icf.h. + +2009-10-11 Ian Lance Taylor + + * plugin.cc: Include "gold.h" before other header files. + +2009-10-10 Chris Demetriou + + * options.h (Input_file_argument::Input_file_type): New enum. + (Input_file_argument::is_lib_): Replace with... + (Input_file_argument::type_): New member. + (Input_file_argument::Input_file_argument): Take Input_file_type + 'type' rather than boolean 'is_lib' as second argument. + (Input_file_argument::is_lib): Use type_. + (Input_file_argument::is_searched_file): New function. + (Input_file_argument::may_need_search): Handle is_searched_file. + * options.cc (General_options::parse_library): Support -l:filename. + (General_options::parse_just_symbols): Update for Input_file_argument + changes. + (Command_line::process): Likewise. + * archive.cc (Archive::get_file_and_offset): Likewise. + * plugin.cc (Plugin_manager::release_input_file): Likewise. + * script.cc (read_script_file, script_add_file): Likewise. + * fileread.cc (Input_file::Input_file): Likewise. + (Input_file::will_search_for): Handle is_searched_file. + (Input_file::open): Likewise. + * readsyms.cc (Read_symbols::get_name): Likewise. + * testsuite/Makefile.am (searched_file_test): New test. + * testsuite/Makefile.in: Regenerate. + * testsuite/searched_file_test.cc: New file. + * testsuite/searched_file_test_lib.cc: New file. + +2009-10-09 Andrew Pinski + Ian Lance Taylor + + * descriptor.cc: Include and "binary-io.h". + (Descriptors::open): Open the files in binary mode always. + * script.cc (Lex::get_token): Treat \r as whitespace. + +2009-10-09 Ian Lance Taylor + + * testsuite/retain_symbols_file_test.sh: Don't test for __tcf_0. + +2009-10-09 Andrew Pinski + Ian Lance Taylor + + * configure.ac: Check for readv function also. + * fileread.cc (readv): Define if not HAVE_READV. + * fileread.h (File_read:: max_readv_entries): Set to 1 if readv + does not exist. + * config.in: Regenerate. + * configure: Regenerate. + +2009-10-09 Doug Kwan + + * layout.cc (Layout::make_output_section): Call target hook to make + ordinary output section. + (Layout::finalize): Adjust parameter list of call the + Target::may_relax(). + * layout.h (class Layout::section_list): New method. + * merge.h (Output_merge_base::entsize): Change visibility to public. + (Output_merge_base::is_string, Output_merge_base::do_is_string): + New methods. + (Output_merge_string::do_is_string): New method. + * object.cc (Sized_relobj::do_setup): renamed from + Sized_relobj::set_up. + * object.h (Sized_relobj::adjust_shndx, + Sized_relobj::initializ_input_to_output_maps, + Sized_relobj::free_input_to_output_maps): Change visibilities to + protected. + (Sized_relobj::setup): Virtualize. + (Sized_relobj::do_setup): New method declaration. + (Sized_relobj::invalidate_section_offset, + Sized_relobj::do_invalidate_section_offset): New method decfinitions. + (Sized_relobj::elf_file, Sized_relobj::local_values): New methods. + * options.cc (parse_int): New function. + * options.h (parse_int): New declaration. + (DEFINE_int): New macro. + (stub_group_size): New option. + * output.cc (Output_section::Output_section): Initialize memebers + merge_section_map_, merge_section_by_properties_map_, + relaxed_input_section_map_, is_relaxed_input_section_map_valid_. + (Output_section::add_input_section): Handled deferred code-fill + generation and remove an old comment. + (Output_section::add_relaxed_input_section): New method definition. + (Output_section::add_merge_input_section): Use merge section by + properties map to speed to search. Update merge section maps + as appropriate. + (Output_section::build_relaxation_map): New method definition. + (Output_section::convert_input_sections_in_list_to_relaxed_sections): + Same. + (Output_section::relax_input_section): Renamed to + Output_section::convert_input_sections_to_relaxed_sections and change + interface to take a vector of pointers to relaxed sections. + (Output_section::find_merge_section, + Output_section::find_relaxed_input_section): New method definitions. + (Output_section::is_input_address_mapped, + Output_section::output_offset, Output_section::output_address): + Use output section data maps to speed up searching. + (Output_section::find_starting_output_address): Add comments. + (Output_section::do_write, + Output_section::write_to_postprocessing_buffer): Do code-fill + generation as appropriate. + (Output_section::get_input_sections): Invalidate relaxed input section + map. + (Output_section::restore_states): Adjust type of checkpoint . + Invalidate relaxed input section map. + * output.h (Output_merge_base): New class declaration. + (Input_section_specifier): New class defintion. + (class Output_relaxed_input_section) Change base class to + Output_section_data_build. + (Output_relaxed_input_section::Output_relaxed_input_section): Adjust + 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::shndx): Handle relaxed input sections. + Output_section::input_sections) Change visibility to protected. Also + define overload to return a non-const pointer. + (Output_section::Merge_section_properties): New class defintion. + (Output_section::Merge_section_by_properties_map, + Output_section::Output_section_data_by_input_section_map, + Output_section::Relaxation_map): New types. + (Output_section::relax_input_section): Rename method to + Output_section::convert_input_sections_to_relaxed_sections and change + interface to take a vector of relaxed section pointers. + (Output_section::find_merge_section, + Output_section::find_relaxed_input_section, + Output_section::build_relaxation_map, + Output_section::convert_input_sections_in_list_to_relaxed_sections): + New method declarations. + (Output_section::merge_section_map_ + Output_section::merge_section_by_properties_map_, + Output_section::relaxed_input_section_map_, + Output_section::is_relaxed_input_section_map_valid_, + Output_section::generate_code_fills_at_write_): New data members. + * script-sections.cc + (Output_section_element_input::set_section_addresses): Call + current_data_size and addralign methods of relaxed input sections. + (Orphan_output_section::set_section_addresses): Call current_data_size + and addralign methods of relaxed input sections. + * symtab.cc (Symbol_table::compute_final_value): Extract template + from the body of Symbol_table::sized_finalize_symbol. + (Symbol_table::sized_finalized_symbol): Call + Symbol_table::compute_final_value. + * symtab.h (Symbol_table::Compute_final_value_status): New enum type. + (Symbol_table::compute_final_value): New templated method declaration. + * target.cc (Target::do_make_output_section): New method defintion. + * target.h (Target::make_output_section): New method declaration. + (Target::relax): Add more parameters for input objects, symbol table + and layout. Adjust call to do_relax. + (Target::do_make_output_section): New method declaration. + (Target::do_relax): Add parameters for input objects, symbol table + and layout. + +2009-10-09 Andrew Pinski + + * pread.c: Include stdio.h. + +2009-10-09 Andrew Pinski + + * plugin.cc: Don't include dlfcn.h when ENABLE_PLUGINS is not + defined. + +2009-10-09 Andrew Pinski + + * dwarf_reader.cc (Sized_dwarf_line_info::Sized_dwarf_line_info): + Change read_shndx type to unsigned int. + (Sized_dwarf_line_info::read_lines): Change shndx type to unsigned + int. + (Sized_dwarf_line_info::read_line_mappings): Likewise. + * dwarf_reader.h (Sized_dwarf_line_info::Sized_dwarf_line_info): + Change read_shndx type to unsigned int. + (Sized_dwarf_line_info::read_lines): Change shndx type to unsigned + int. + (Sized_dwarf_line_info::read_line_mappings): Likewise. + * layout.cc (Layout::create_symtab_sections): Cast the result of + local_symcount * symsize to off_t in the gold_assert. + +2009-10-09 Viktor Kutuzov + + * arm.cc (Target_arm::relocate::reloc_is_non_pic): Return true for + R_ARM_THM_ABS5, R_ARM_ABS8, R_ARM_ABS12, R_ARM_ABS16, + R_ARM_BASE_ABS. + (Arm_relocate_functions::abs8): Remove has_thumb_bit parameter. + (Arm_relocate_functions::thm_abs5): New function. + (Arm_relocate_functions::abs12): New function. + (Arm_relocate_functions::abs16): New function. + (Arm_relocate_functions::base_abs): New function. + (Scan::check_non_pic): Handle R_ARM_ABS32_NOI. + (Scan::local): Remove special handling of R_ARM_ABS8. Handle + R_ARM_ABS32_NOI, R_ARM_THM_ABS5, R_ARM_ABS12, R_ARM_ABS16, and + R_ARM_BASE_ABS. + (Scan::global): Likewise. + (Relocate::relocate): Handle R_ARM_ABS12, R_ARM_ABS16, + R_ARM_ABS32_NOI, R_ARM_THM_ABS5, and R_ARM_BASE_ABS. + (Relocatable_size_for_reloc::get_size_for_reloc): Handle + R_ARM_ABS16, R_ARM_THM_ABS5, R_ARM_ABS32_NOI, R_ARM_ABS12, and + R_ARM_BASE_ABS. + +2009-10-09 Viktor Kutuzov + + * arm.cc (Arm_relocate_functions::movw_prel_nc): New function. + (Arm_relocate_functions::movt_prel): New function. + (Arm_relocate_functions::thm_movw_prel_nc): New function. + (Arm_relocate_functions::thm_movt_prel): New function. + (Scan::local): Handle R_ARM_MOVW_PREL_NC, R_ARM_MOVT_PREL, + R_ARM_THM_MOVW_PREL_NC, and R_ARM_THM_MOVT_PREL. + (Scan::global, Relocate::relocate): Likewise. + (Relocatable_size_for_reloc::get_size_for_reloc): Likewise. + +2009-10-09 Mikolaj Zalewski + + * gold.cc: (queue_initial_tasks): Pass incremental_inputs to + Incremental_checker. + * incremental.cc: (INCREMENTAL_LINK_VERSION): Change type to + unsigned int. + (class Incremental_inputs_header): New class. + (Incremental_inputs_header_writer): Edit comment. + (Incremental_inputs_entry): New class. + (Incremental_inputs_entry_writer): Edit comment. + (Sized_incremental_binary::do_find_incremental_inputs_section): + Add *strtab_shndx parameter, fill it. + (Sized_incremental_binary::do_check_inputs): New method. + (Incremental_checker::can_incrementally_link_output_file): Use + Sized_incremental_binary::check_inputs. + (Incremental_inputs::report_command_line): Save command line in + command_line_. + * incremental.h: + (Incremental_binary::find_incremental_inputs_section): New + method. + (Incremental_binary::do_find_incremental_inputs_section): Add + strtab_shndx parameter. + (Incremental_binary::do_check_inputs): New pure virtual method. + (Sized_incremental_binary::do_check_inputs): Declare. + (Incremental_checker::Incremental_checker): Add incremental_inputs + parameter, use it to initialize incremental_inputs_. + (Incremental_checker::incremental_inputs_): New field. + (Incremental_checker::command_line): New method. + (Incremental_checker::inputs): New method. + (Incremental_checker::command_line_): New field. + +2009-10-09 Mikolaj Zalewski + + * incremental.cc: Include and "target-select.h". + (vexplain_no_incremental): New function. + (explain_no_incremental): New function. + (Incremental_binary::error): New method. + (Sized_incremental_binary::do_find_incremental_inputs_section): New + method. + (make_sized_incremental_binary): New function. + (open_incremental_binary): New function. + (can_incrementally_link_file): Add checks if output is ELF and has + inputs section. + * incremental.h: Include "elfcpp_file.h" and "output.h". + (Incremental_binary): New class. + (Sized_incremental_binary): New class. + (open_incremental_binary): Declare. + * object.cc (is_elf_object): Use + elfcpp::Elf_recognizer::is_elf_file. + (make_elf_object): Use elfcpp::Elf_recognizer::is_valid_header. + * output.h (Output_file::filesize): New method. + +2009-10-07 Viktor Kutuzov + + * arm.cc (Arm_relocate_functions::extract_arm_movw_movt_addend): + New function. + (Arm_relocate_functions::insert_val_arm_movw_movt): New function. + (Arm_relocate_functions::extract_thumb_movw_movt_addend): New + function. + (Arm_relocate_functions::insert_val_thumb_movw_movt): New + function. + (Arm_relocate_functions::movw_abs_nc): New function. + (Arm_relocate_functions::movt_abs): New function. + (Arm_relocate_functions::thm_movw_abs_nc): New function. + (Arm_relocate_functions::thm_movt_abs): New function. + (Scan::local): Handle R_ARM_MOVW_ABS_NC, R_ARM_MOVT_ABS, + R_ARM_THM_MOVW_ABS_NC, R_ARM_THM_MOVT_ABS. + (Scan::global): Likewise. + (Relocate::relocate): Likewise. + (Relocatable_size_for_reloc::get_size_for_reloc): Likewise. + +2009-10-07 Viktor Kutuzov + + * arm.cc (Arm_relocate_functions::got_prel) New function. + (Scan::local, Scan::global): Handle R_ARM_GOT_PREL. + (Relocate::relocate): Likewise. + (Relocatable_size_for_reloc::get_size_for_reloc): Likewise. + +2009-10-06 Ian Lance Taylor + + * options.h (class General_options): Define + split_stack_adjust_size parameter. + * object.h (class Object): Add uses_split_stack_ and + has_no_split_stack_ fields. Add uses_split_stack and + has_no_split_stack accessor functions. Declare + handle_split_stack_section. + (class Reloc_symbol_changes): Define. + (class Sized_relobj): Define Function_offsets. Declare + split_stack_adjust, split_stack_adjust_reltype, and + find_functions. + * object.cc (Object::handle_split_stack_section): New function. + (Sized_relobj::do_layout): Call handle_split_stack_section. + * dynobj.cc (Sized_dynobj::do_layout): Call + handle_split_stack_section. + * reloc.cc (Sized_relobj::relocate_sections): Call + split_stack_adjust for executable sections in split_stack + objects. Pass reloc_map to relocate_section. + (Sized_relobj::split_stack_adjust): New function. + (Sized_relobj::split_stack_adjust_reltype): New function. + (Sized_relobj::find_functions): New function. + * target-reloc.h: Include "object.h". + (relocate_section): Add reloc_symbol_changes parameter. Change + all callers. + * target.h (class Target): Add calls_non_split method. Declare + do_calls_non_split virtual method. Declare match_view and + set_view_to_nop. + * target.cc: Include "elfcpp.h". + (Target::do_calls_non_split): New function. + (Target::match_view): New function. + (Target::set_view_to_nop): New function. + * gold.cc (queue_middle_tasks): Give an error if mixing + split-stack and non-split-stack objects with -r. + * i386.cc (Target_i386::relocate_section): Add + reloc_symbol_changes parameter. + (Target_i386::do_calls_non_split): New function. + * x86_64.cc (Target_x86_64::relocate_section): Add + reloc_symbol_changes parameter. + (Target_x86_64::do_calls_non_split): New function. + * arm.cc (Target_arm::relocate_section): Add reloc_symbol_changes + parameter. + * powerpc.cc (Target_powerpc::relocate_section): Add + reloc_symbol_changes parameter. + * sparc.cc (Target_sparc::relocate_section): Add + reloc_symbol_changes parameter. + * configure.ac: Call AM_CONDITIONAL for the default target. + * configure: Rebuild. + * testsuite/Makefile.am (TEST_AS): New variable. + (check_SCRIPTS): Add split_i386.sh and split_x86_64.sh. + (check_DATA): Add split_i386 and split_x86_64 files. + (SPLIT_DEFSYMS): Define. + (split_i386_[1234n].o): New targets. + (split_i386_[124]): New targets. + (split_i386_[1234r].stdout): New targets. + (split_x86_64_[1234n].o): New targets. + (split_x86_64_[124]): New targets. + (split_x86_64_[1234r].stdout): New targets. + (MOSTLYCLEANFILES): Add new executables. + * testsuite/split_i386.sh: New file. + * testsuite/split_x86_64.sh: New file. + * testsuite/split_i386_1.s: New file. + * testsuite/split_i386_2.s: New file. + * testsuite/split_i386_3.s: New file. + * testsuite/split_i386_4.s: New file. + * testsuite/split_i386_n.s: New file. + * testsuite/split_x86_64_1.s: New file. + * testsuite/split_x86_64_2.s: New file. + * testsuite/split_x86_64_3.s: New file. + * testsuite/split_x86_64_4.s: New file. + * testsuite/split_x86_64_n.s: New file. + * testsuite/testfile.cc (Target_test): Update relocation_section + function. + * testsuite/Makefile.in: Rebuild. + +2009-10-06 Ian Lance Taylor + + * i386.cc (class Target_i386::Relocate): Add ldo_addrs_ field. + (Target_i386::Relocate::relocate_tls): Call fix_up_ldo before + changing local_dynamic_type_ from LOCAL_DYNAMIC_NONE. When + handling R_386_TLS_LDO_32, if local_dynamic_type_ is NONE, push + the address on ldo_addrs_. + (Target_i386::Relocate::fix_up_ldo): New function. + +2009-10-06 Rafael Espindola + + * plugin.cc (add_input_library): New. + (Plugin::load): Add add_input_library to tv. + (Plugin_manager::add_input_file): Add the is_lib argument. + (add_input_file): Update call to Plugin_manager::add_input_file. + (add_input_library): New. + * plugin.h (Plugin_manager::add_input_file): Add the is_lib argument. + +2009-09-30 Doug Kwan + + * arm.cc (Target_arm::may_need_copy_reloc): Check for THUMB function + symbol and call Symbol::may_need_copy_reloc to determine if + a copy reloc is needed. + * copy-relocs.cc (Copy_relocs::need_copy_reloc): Return false if -z + nocopyreloc is given in command line. + (Copy_relocs::emit_copy_reloc): Assert that -z nocopyreloc is not + given in command line. + * i386.cc (Target_i386::may_need_copy_reloc): Remove. + (Target_i386::Scan::global): Use Symbol::may_need_copy_reloc instead + of the removed Target_i386::may_need_copy_reloc. + * options.h (copyreloc): New option with default value false. + * powerpc.cc (Target_powerpc::may_need_copy_reloc): Remove. + (Target_powerpc::Scan::global): Use Symbol::may_need_copy_reloc + instead of the removed Target_powerpc::may_need_copy_reloc. + * sparc.cc (Target_powerpc::may_need_copy_reloc): Remove. + (Target_sparc::Scan::global): Use Symbol::may_need_copy_reloc + instead of the removed Target_sparc::may_need_copy_reloc. + * symtab.h (Symbol::may_need_copy_reloc): New method definition. + * x86_64.cc (Target_powerpc::may_need_copy_reloc): Remove. + (Target_x86_64::Scan::global): Use Symbol::may_need_copy_reloc + instead of the removed Target_x86_64::may_need_copy_reloc. + +2009-09-30 Ian Lance Taylor + + * object.h (class Object): Remove target_ field, and target, + sized_target, and set_target methods. + (Object::sized_target): Remove. + (class Sized_relobj): Update declarations. Remove sized_target. + * object.cc (Sized_relobj::setup): Remove target parameter. + Change all callers. + (Input_objects::add_object): Don't do anything with the target. + (make_elf_sized_object): Add punconfigured parameter. Change all + callers. Set or test parameter target. + * dynobj.cc (Sized_dynobj::target): Remove target parameter. + Change all callers. + * parameters.cc (Parameters::set_target): Change parameter type to + be non-const. + (Parameters::default_target): Remove. + (set_parameters_target): Change parameter type to be non-const. + (parameters_force_valid_target): New function. + (parameters_clear_target): New function. + * parameters.h (class Parameters): Update declarations. Remove + default_target method. Add sized_target and clear_target + methods. Change target_ to be non-const. + (set_parameters_target): Update declaration. + (parameters_force_valid_target): Declare. + (parameters_clear_target): Declare. + * readsyms.cc (Read_symbols::do_read_symbols): Pass punconfigured + as NULL if we aren't searching. + (Add_symbols::run): Don't check for compatible target. + * fileread.cc (Input_file::open_binary): Call + parameters_force_valid_target. + * gold.cc (queue_middle_tasks): Likewise. + * plugin.cc (make_sized_plugin_object): Likewise. Don't call + set_target on object. + * dynobj.h (class Sized_dynobj): Update declarations. + * archive.cc (Archive::get_elf_object_for_member): Return NULL if + make_elf_object returns NULL. + (Archive::include_member): Don't check whether object target is + compatible. + * output.cc (Output_section::add_input_section): Get target from + parameters. + (Output_section::relax_input_section): Likewise. + * reloc.cc (Sized_relobj::do_gc_process_relocs): Get target from + parameters. + (Sized_relobj::do_scan_relocs): Likewise. + (Sized_relobj::relocate_sections): Likewise. + * resolve.cc (Symbol_table::resolve): Likewise. + * symtab.cc (Symbol_table::wrap_symbol): Likewise. Remove object + parameter. Change all callers. + (Symbol_table::add_from_object): Get target from parameters. + (Symbol_table::add_from_relobj): Don't check object target. + (Symbol_table::add_from_dynobj): Likewise. + (Symbol_table::define_special_symbol): Get target from + parameters. + * symtab.h (class Symbol_table): Update declaration. + * testsuite/binary_unittest.cc (gold_testsuite): Remove target + parameter. Change all callers. Clear parameter target. + (Binary_test): Test target here. + * testsuite/object_unittest.cc (gold_testsuite): Remove + target_test_pointer parameter. Change all callers. + (Object_test): Test target here. + +2009-09-26 Ian Lance Taylor + + * testsuite/initpri1.c: Don't try to use constructor priorities if + compiling with gcc before 4.3. + +2009-09-22 Mikolaj Zalewski + + * testsuite/retain_symbols_file_test.sh (check_present): Change + output file name to retain_symbols_file_test.stdout. + (check_absent): Likewise. + +2009-09-18 Craig Silverstein + + * object.cc (Sized_relobj::do_count): Test should_retain_symbol map. + * options.cc: Include and . + (General_options::finalize): Parse -retain-symbols-file tag. + * options.h: New flag. + (General_options): New method should_retain_symbol, new + variable symbols_to_retain. + * symtab.cc (Symbol_table::sized_finalize_symbol): Test + should_retain_symbol map. + * testsuite/Makefile.am (retain_symbols_file_test): New test. + * testsuite/Makefile.in: Regenerate. + * testsuite/retain_symbols_file_test.sh: New file. + +2009-09-18 Nick Clifton + + * po/es.po: Updated Spanish translation. + +2009-09-17 Doug Kwan + + * debug.h (DEBUG_RELAXATION): New constant. + (DEBUG_ALL): Add DEBUG_RELAXATION. + (debug_string_to_enum): Add relaxation debug option. + * layout.cc + (Layout::Relaxation_debug_check::check_output_data_for_reset_values, + Layout::Relaxation_debug_check::read_sections, + Layout::Relaxation_debug_check::read_sections): New method definitions. + (Layout::Layout): Initialize data members + record_output_section_data_from_scrips_, + script_output_section_data_list_ and relaxation_debug_check_. + (Layout::save_segments, Layout::restore_segments, + Layout::clean_up_after_relaxation, Layout::prepare_for_relaxation, + Layout::relaxation_loop_body): New method definitions. + (Layout::finalize): Support relaxation. Move section layout code to + Layout::relaxation_loop_body. + (Layout::set_asection_address_from_script): Move code for orphan + section placement out. + (Layout::place_orphan_sections_in_script): New method definition. + * layout.h (Output_segment_headers, Output_file_header): + New forward class declarations. + (Layout::~Layout): Define. + (Layout::new_output_section_data_from_script): New method definition. + (Layout::place_orphan_sections_in_script): New method declaration. + (Layout::Segment_states): New type declaration. + (Layout::save_segments, Layout::restore_segments, + Layout::clean_up_after_relaxation, Layout::prepare_for_relaxation, + Layout::relaxation_loop_body): New method declarations. + (Layout::Output_section_data_list): New type declaration. + (Layout::Relaxation_debug_check): New class definition. + (Layout::record_output_section_data_from_script_, + Layout::script_output_section_data_list_, Layout::segment_states_, + Layout::relaxation_debug_check_): New data members. + * output.cc: (Output_section_headers::do_size): New method definition. + (Output_section_headers::Output_section_headers): Move size + computation to Output_section_headers::do_size. + (Output_segment_headers::do_size): New method definition. + (Output_file_header::Output_file_header): Move size computation to + Output_file_header::do_size and call it. + (Output_file_header::do_size): New method definition. + (Output_data_group::Output_data_group): Adjust call to + 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 + RELAXED_INPUT_SECTION_CODE. + (Output_section::Output_section): Initialize data member checkpoint_. + (Output_section::~Output_section): Delete checkpoint object pointed + by checkpoint_. + (Output_section::add_input_section): Always add an Input_section if + relaxing. + (Output_section::add_merge_input_section): Add assert. + (Output_section::relax_input_section): New method definition. + (Output_section::set_final_data_size): Set load address to zero for + an unallocated section. + (Output_section::do_address_and_file_offset_have_reset_values): + New method definition. + (Output_section::Input_section_sort_enty::Input_section_sort_enty): + Handle relaxed input section. + (Output_section::sort_attached_input_sections): Checkpoint input + section list lazily. + (Output_section::get_input_sections): Change type of input_sections to + list of Simple_input_section pointers. Checkpoint input section list + lazily. Also handle relaxed input sections. + (Output_section::add_input_section_for_script): Take a reference to + a Simple_input_section object instead of Relobj pointer and section + index as parameter. Handle relaxed input sections. + (Output_section::save_states, Output_section::restore_states): New + method definitions. + * output.h (Output_data::Output_data): Initialize is_data_size_fixed_. + (Output_data::is_data_size_fixed): New method definition. + (Output_data::reset_addresss_and_file_offset): Do not reset data size + if it is fixed. + (Output_data::address_and_file_offset_have_reset_values): New method + definition. + (Output_data::do_address_and_file_offset_have_reset_values): New method + definition. + (Output_data::set_data_size): Check that data size is not fixed. + (Output_data::fix_data_size): New method definition. + (Output_data::is_data_size_fixed_): New data member. + (Output_section_headers::set_final_data_size): New method definition. + (Output_section_headers::do_size): New method declaration. + (Output_segment_headers::set_final_data_size): New method definition. + (Output_segment_headers::do_size): New method declaration. + (Output_file_header::set_final_data_size)::New method definition. + (Output_file_header::do_size)::New method declaration. + (Output_section_data::Output_section_data): Add new parameter + is_data_size_fixed and use it to fix data size. + (Output_data_const::Output_data_const): Adjust call to base class + constructor and fix data size. + (Output_data_const_buffer::Output_data_const_buffer): Adjust call to + base class constructor and fix data size. + (Output_data_fixed_space::Output_data_fixed_space): Adjust call to + base class constructor and fix data size. + (Output_data_zero_fill::Output_data_zero_fill): Adjust call to base + class constructor and fix data size. + (Output_data_group::set_final_data_size): New method definition. + (Output_data_dynamic::Dynamic_entry::tag): New method definition. + (Output_symtab_xindex::Output_symtab_xindex): Adjust call to base + class constructor and fix data size. + (Output_relaxed_input_section): New class definition. + (Output_section::Simple_input_section): New class definition. + (Output_section::get_input_sections): Adjust parameter list. + (Output_section::add_input_section_for_script): Same. + (Output_section::save_states, Output_section::restore_states, + Output_section::do_address_and_file_offset_have_reset_values, + (Output_section::Input_section::Input_section): Handle + RELAXED_INPUT_SECTION_CODE. Add new overload for + Output_relaxed_input_section. + (Output_section::Input_section::is_input_section, + Output_section::Input_section::set_output_section): Handle relaxed + input section. + (Output_section::Input_section::is_relaxed_input_section, + Output_section::Input_section::output_section_data, + Output_section::Input_section::relaxed_input_section): New method + definitions. + (Output_section::Input_section::RELAXED_INPUT_SECTION_CODE): New enum + value. + (Output_section::Input_section::u1_): Update comments. + (Output_section::Input_section::u2_): Add new union member poris. + (Output_section::Checkpoint_output_section): New classs definition. + (Output_section::relax_input_section): New method declaration. + (Output_section::checkpoint_): New data member. + (Output_segment): Update comments. + (Output_segment::Output_segment): Un-privatize copy constructor. + (Output_segment::operator=): Un-privatize. + * script-sections.cc (Output_section_element::Input_section_list): + Change element type to Output_section::Simple_input_section. + (Output_section_element_dot_assignment::set_section_addresses): + Register output section data for relaxation clean up. + (Output_data_exression::Output_data_expression): Adjust call to base + constructor to fix data size. + (Output_section_element_data::set_section_addresses): Register + Output_data_expression object for relaxation clean up. + (struct Input_section_info): Replace Relobj pointer and section index + pair with Output_section::Simple_input_section and Convert struct to a + class. + (Input_section_sorter::operator()): Adjust access to + Input_section_info data member to use accessors. + (Output_section_element_input::set_section_addresses): Use layout + parameter. Adjust code to use Output_section::Simple_input_section + and Input_secction_info classes. Register filler for relaxation + clean up. + (Orphan_output_section::set_section_addresses): Replace Relobj pointer + and section index pair with Output_section::Simple_input_section + class. Adjust code accordingly. + (Phdrs_element::release_segment): New method definition. + (Script_sections::attach_sections_using_phdrs_clause): Do not modify + segment list. + (Script_sections::release_segments): New method definition. + * gold/script-sections.h (Script_sections::release_segments): New + method declaration. + * gold/target.h (Target::may_relax, Target::relax, + Target::do_may_relax, Target::do_relax): New method definitions. + +2009-09-17 Viktor Kutuzov + + * arm.cc (has_signed_unsigned_overflow): New function. + (Arm_relocate_functions::abs8): New function. + (Target_arm::Scan::local): Handle R_ARM_ABS8. + (Target_arm::Scan::global): Likewise. + (Target_arm::relocate::relocate): Likewise. + (Target_arm::Relocatable_size_for_reloc::get_size_for_reloc): + Likewise. + +2009-09-16 Cary Coutant + + * testsuite/Makefile.am (MOSTLYCLEANFILES): Add more generated files. + * testsuite/Makefile.in: Regenerate. + +2009-09-11 Nick Clifton + + * po/gold.pot: Updated by the Translation project. + +2009-09-08 Cary Coutant + + * output.cc (Output_file::open): Add execute permission to empty file. + * testsuite/Makefile.am (permission_test): New test. + * testsuite/Makefile.in: Regenerate. + +2009-09-02 Ian Lance Taylor + + * output.cc (Output_file::resize): Call map_no_anonymous rather + than map. + +2009-09-01 Mikolaj Zalewski + + * gold.cc: Include "incremental.h". + (queue_initial_tasks): Call Incremental_checker methods. + * incremental.cc: Include "output.h". + (Incremental_checker::can_incrementally_link_output_file): New + method. + * incremental.h (Incremental_checker): New class. + + * output.cc (Output_file::open_for_modification): New method. + (Output_file::map_anonymous): Changed return type to bool. Record + map in base_ field. + (Output_file::map_no_anonymous): New method, broken out of map. + (Output_file::map): Use map_no_anonymous and map_anonymous. + * output.h (class Output_file): Update declarations. + +2009-08-24 Cary Coutant + + * options.h (Command_line::Pre_options): New class. + (Command_line::pre_options): New member. + * options.cc (gold::options::ready_to_register): New variable. + (One_option::register_option): Do nothing if not registering options. + Assert if same short option registered twice. + (General_options::General_options): Turn off option registration when + done constructing. + (Command_line::Pre_options::Pre_options): New constructor. + +2009-08-24 Cary Coutant + + * options.h (General_options::no_keep_memory): Remove incorrect + short option. + +2009-08-24 Ralf Wildenhues + + * Makefile.am (am__skiplex, am__skipyacc): New. + * Makefile.in: Regenerate. + +2009-08-22 Ralf Wildenhues + + * Makefile.am (AM_CPPFLAGS): Renamed from ... + (INCLUDES): ... this. + * testsuite/Makefile.am (AUTOMAKE_OPTIONS): Add -Wno-portability. + (AM_CPPFLAGS): Renamed from ... + (INCLUDE): ... this. + * Makefile.in, testsuite/Makefile.in: Regenerate. + + * Makefile.in: Regenerate. + * aclocal.m4: Likewise. + * config.in: Likewise. + * configure: Likewise. + * testsuite/Makefile.in: Likewise. + + * Makefile.am (AUTOMAKE_OPTIONS): Add foreign. + * testsuite/Makefile.am (AUTOMAKE_OPTIONS): Add foreign. + * Makefile.in: Regenerate. + * testsuite/Makefile.in: Regenerate. + +2009-08-19 Cary Coutant + + * resolve.cc (Symbol_table::resolve): Don't complain about defined + symbols in shared libraries overridden by hidden or internal symbols + in the main program. + +2009-08-19 Chris Demetriou + + * testsuite/debug_msg.sh: Match .* rather than ${srcdir} when + checking source file names in error messages. + +2009-08-18 Doug Kwan + + * dynobj.cc (Sized_dynobj::setup): Take a Target object instead of + an elcpp::Ehdr as parameter. Adjust call to set_target. + * dynobj.h (Sized_dynobj::setup): Take a Target object instead of + an elfcpp::Ehdr as parameter. + * object.cc (Object::set_target): Remove the version that looks up + a target and sets it. + (Sized_relobj::setup): Take a Target object instead of + an elfcpp::Ehdr as parameter. Adjust call to set_target. + (make_elf_sized_object): Find target and ask target to + make an ELF object. + * object.h: (Object::set_target): Remove the version that looks up + a target and sets it. + (Sized_relobj::setup): Take a Target object instead of + an elfcpp:Ehdr as parameter. + * target.cc: Include dynobj.h. + (Target::do_make_elf_object_implementation): 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. + +2009-08-14 Ian Lance Taylor + + * gold.h (FUNCTION_NAME): Define. + (gold_unreachable): Use FUNCTION_NAME. + +2009-08-12 Sriraman Tallam + + * icf.cc (Icf::find_identical_sections): Issue a warning when a + symbol in the --keep-unique list is not found. + +2009-08-12 Sriraman Tallam + + * icf.cc (Icf::find_identical_sections): Unfold symbols that have + been maked as --keep-unique. + (Icf::unfold_section): New function. + * icf.h (Icf::unfold_section): New function. + * options.h (General_options::keep_unique): New option. + * testsuite/Makefile.am: Add commands to build icf_keep_unique_test. + * testsuite/Makefile.in: Regenerate. + * testsuite/icf_keep_unique_test.sh: New file. + * testsuite/icf_keep_unique_test.cc: New file. + +2009-08-12 Cary Coutant + + PR 10471 + * resolve.cc (Symbol_table::resolve): Check for references from + dynamic objects to hidden and internal symbols. + * testsuite/Makefile.am (hidden_test.sh): New test. + * testsuite/Makefile.in: Regenerate. + * testsuite/hidden_test.sh: New script. + * testsuite/hidden_test_1.c: New test source. + * testsuite/hidden_test_main.c: New test source. + +2009-08-11 Doug Kwan + + * arm.cc: Update comments. + (Target_arm::do_finalize_sections): Add a special PT_ARM_EXIDX + segment to locate the .ARM.exidx section if present. + +2009-08-09 Doug Kwan + + * dynobj.h (Sized_dynobj::do_section_entsize): Revert the previous + patch. + +2009-08-07 Sriraman Tallam + * dynobj.h (Sized_dynobj::do_section_entsize): Add return to avoid + compiler warnings. + +2009-08-06 Sriraman Tallam + + * x86_64.cc (Target_x86_64::Relocate::relocate_tls): Check for a + valid tls_segment only for non-debug-section relocations. + * testsuite/Makefile.am: Add gc_tls_test. + * testsuite/Makefile.in: Regenerate. + * testsuite/gc_tls_test.cc: New file. + * testsuite/gc_tls_test.sh: New file. + +2009-08-05 Sriraman Tallam + + * icf.cc: New file. + * icf.h: New file. + * Makefile.am (CCFILES): Add icf.cc. + (HFILES): Add icf.h + * Makefile.in: Regenerate. + * dynobj.h (Sized_dynobj::do_section_entsize): New function. + * gc.h (gc_process_relocs): Populate lists used by icf to contain + section, symbol and addend information for the relocs. + * gold.cc (queue_middle_tasks): Call identical code folding. + * gold.h: Add defines for multimap. + * layout.cc (Layout::create_symtab_sections): Add symtab as parameter + to the call of finalize_local_symbols. + * main.cc (main): Create object of class Icf. + * object.cc (Sized_relobj::do_layout): Allow this function to be + called twice during icf. + (Sized_relobj::do_finalize_local_symbols): Fold symbols corresponding + to sections marked as identical by icf. + (Sized_relobj::do_section_flags): Get section_flags from Symbols_data + when available. + (Sized_relobj::do_section_entsize): New function. + * object.h (Object::section_entsize): New function. + (Object::do_section_entsize): New pure virtual function. + (Relobj::finalize_local_symbols): Add new parameter. + (Relobj::do_section_entsize): New function. + * options.h (General_options::icf): New option. + (General_options::icf_iterations): New option. + (General_options::print_icf_sections): New option. + * plugin.cc (Sized_pluginobj::do_section_entsize): New function. + * plugin.h (Sized_pluginobj::do_section_entsize): New function. + * reloc.cc (Read_relocs::run): Delay scanning relocs when doing + icf. + * symtab.cc (Symbol_table::is_section_folded): New function. + (Symbol_table::sized_finalize_symbol): Fold symbols corresponding + to sections marked as identical by icf. + * symtab.h (Symbol_table::set_icf): New function. + (Symbol_table::icf): New function. + (Symbol_table::is_section_folded): New function. + (Symbol_table::icf_): New data member. + * target-reloc.h (relocate_section): Ignore sections folded by icf. + * testsuite/Makefile.am: Add commands to build icf_test. + * testsuite/Makefile.in: Regenerate. + * testsuite/icf_test.sh: New file. + * testsuite/icf_test.cc: New file. + +2009-07-24 Chris Demetriou + + * layout.cc (is_compressible_debug_section): Fix incorrect + comment about compressed section names. + +2009-07-20 Ian Lance Taylor + + PR 10419 + * x86_64.cc (Target_x86_64::do_code_fill): Correct nop sequences. + +2009-07-16 Ian Lance Taylor + + PR 10400 + * layout.h: #include . + (class Kept_section): Change from struct to class. Add accessors + and setters. Add section size to Comdat_group mapping. Change + Comdat_group to std::map. Add is_comdat_ field. Add + linkonce_size field in union. + (class Layout): Update declaration of find_or_add_kept_section. + Don't declare find_kept_object. + * layout.cc (Layout::find_or_add_kept_section): Remove candidate + parameter. Add object, shndx, is_comdat, and is_group_name + parameters. Change all callers. Adjust for new Kept_section. + (Layout::find_kept_object): Remove. + * object.cc (Sized_relobj::include_section_group): Update use of + Kept_section. Rename secnum to shndx. Only record + Kept_comdat_section if sections are the same size. + (Sized_relobj::include_linkonce_section): Update use of + Kept_section. Only record Kept_comdat_section if sections are the + same size. Set size of linkonce section. + (Sized_relobj::map_to_kept_section): Update call to + get_kept_comdat_section. + * object.h (class Sized_relobj): Rename fields in + Kept_comdat_section to drop trailing underscores; change object + field to Relobj*. Change Kept_comdat_section_table to store + struct rather than pointer. + (Sized_relobj::set_kept_comdat_section): Remove kept parameter. + Add kept_object and kept_shndx parameters. Change all callers. + (Sized_relobj::get_kept_comdat_section): Change return type to + bool. Add kept_object and kept_shndx parameters. Change all + callers. + * plugin.cc (Pluginobj::include_comdat_group): Update call to + Layout::find_or_add_kept_section. + +2009-07-09 Ian Lance Taylor + + * merge.cc (Object_merge_map::initialize_input_to_output_map): + Reserve space in the hash table. + +2009-07-06 Mikolaj Zalewski + + * fileread.cc (File_read::get_mtime): New method. + * fileread.h (Timespec): New structure. + (File_read::get_mtime): New method. + * incremental.cc (Incremental_inputs_entry_data::timestamp_usec): + Renamed from timestamp_nsec. + (Incremental_inputs_entry_write::timestamp_sec): Fix argument to + Elf_Xword. + (Incremental_inputs_entry_write::timestamp_usec): Renamed from + timestamp_nsec. + (Incremental_inputs::report_archive): Save mtime; style fix. + (Incremental_inputs::report_obejct): Save mtime; style fix. + (Incremental_inputs::report_script): Save mtime; style fix. + (Incremental_inputs::finalize_inputs): Style fix. + (Incremental_inputs::finalize): Style fix. + (Incremental_inputs::create_input_section_data): Store inputs + mtime. + * incremental.h (Incremental_inputs::report_script): Add mtime + argument. + (Incremental_inputs::Input_info::Input_info): Intialize only one + union member. + (Incremental_inputs::Input_info::archive): Move to nameless + union. + (Incremental_inputs::Input_info::obejct): Move to nameless union. + (Incremental_inputs::Input_info::script): Move to nameless union. + (Incremental_inputs::mtime): New field. + * script.cc (read_input_script): Pass file mtime to + Incremental_input. + * script.h (Script_info::inputs): Style fix. + +2009-07-01 Ian Lance Taylor + + * freebsd.h (Target_freebsd::do_adjust_elf_header): Use size + instead of 32. + +2009-06-24 Ian Lance Taylor + + PR 10156 + * layout.cc (Layout::choose_output_section): If we find an + existing section, update the flags. + (Layout::create_notes): New function, broken out of + Layout::finalize. + (Layout::finalize): Don't create note sections. + (Layout::create_note): Don't crash if linker script discards + section. + (Layout::create_gold_note): Likewise. + (Layout::create_build_id): Likewise. Don't set + after_input_sections on the section. + (Layout::create_executable_stack_info): Remove target parameter. + Change caller. + * layout.h (class Layout): Declare create_notes. Update + declaration of create_executable_stack_info. + * gold.cc (queue_middle_tasks): Call create_notes. + * output.cc (Output_section::update_flags_for_input_section): Move + here from output.h. If SHF_ALLOC flag is newly set, mark address + invalid. + * output.h (Output_data::mark_address_invalid): New function. + (class Output_section): Only declare, not define, + update_flags_for_input_section. Remove set_flags. + +2009-06-24 Ian Lance Taylor + + * script-sections.cc (Output_section_definition:: + set_section_addresses): Rename shadowing local load_address to + laddr. + +2009-06-24 Ian Lance Taylor + + PR 10244 + * reloc.cc (relocate_sections): Skip empty relocation sections. + +2009-06-23 Ian Lance Taylor + + PR 10156 + * layout.cc (Layout::create_note): Use choose_output_section + rather than make_output_section. + +2009-06-23 Ian Lance Taylor + + PR 10237 + * options.cc (General_options::parse_V): Set printed_version_. + (General_options::General_options): Initialize printed_version_. + * options.h (class General_options): Add printed_version_ field. + * gold.cc (queue_initial_tasks): If there are no input files, + don't give a fatal error if we printed the version information. + (queue_middle_tasks): If using -r with a shared object, give a + fatal error rather than an ordinary error. + +2009-06-23 Ian Lance Taylor + + PR 10219 + * layout.cc (Layout::Layout): Initialize have_stabstr_section_. + (Layout::make_output_section): Set have_stabstr_section_ if we see + a .stab*str section. + (Layout::finalize): Call link_stabs_sections. + (Layout::link_stabs_sections): New file. + * layout.h (class Layout): Add have_stabstr_section_ field. + Declare link_stabs_sections. + +2009-06-23 Doug Kwan + + * Makefile.am (libgold_a_LIBADD): New. + (ld_new_DEPENDENCIES, ld_new_LDADD): Remove LIBOBJS + * Makefile.in: Regenerate. + * config.in (HAVE_DECL_MEMMEM, HAVE_DECL_STRNDUP): New. + * configure: Regenerate. + * configure.ac (AC_CHECK_DECLS): Add strndup and memmem. + * fileread.cc: Include sys/state.h + * gold.h: Declare memmem and strndup if found missing. + * gold_reloc.h: Include byteswap.h if HAVE_BYTESWAP_H is defined. + +2009-06-23 Ian Lance Taylor + + * configure.ac: Call AC_CHECK_DECLS using C, not C++. + * configure: Rebuild. + +2009-06-23 Ian Lance Taylor + + PR 10147 + * object.cc (Object::section_contents): Don't try to get a view if + the section has length zero. + (Object::handle_gnu_warning_section): If the section is empty, use + the name of the section as the warning. + +2009-06-23 Ian Lance Taylor + + PR 10133 + * stringpool.h (class Stringpool_template): Add optimize_ field. + (Stringpool_template::set_optimize): New function. + * stringpool.cc (Stringpool_template::Stringpool_template): + Initialize optimize_ field. + (Stringpool_template::set_string_offsets): Test local optimize + fild rather than parameter. + * layout.cc (Layout::Layout): Call set_optimize on the section + name stringpool. + +2009-06-22 Ian Lance Taylor + + PR 10030 + * yyscript.y: Parse TARGET. + * script.cc (script_set_target): New function. + * script-c.h (script_set_target): Declare. + * options.cc (General_options::string_to_object_format): Rename + from string_to_object_format in anonymous namespace. Change + callers. + * options.h (class General_options): Declare + string_to_object_format. + +2009-06-22 Ian Lance Taylor + + * script-sections.cc (Script_sections::create_segments): Don't put + program headers in a PT_LOAD segment if -n or -N. + +2009-06-22 Ian Lance Taylor + + PR 10141 + * options.h (class General_options): Add -z lazy and -z now. Sort + -z options into alphabetical order. + * layout.cc (Layout::finish_dynamic_section): Handle -z now. + +2009-06-21 Ian Lance Taylor + + * layout.cc (Layout::make_output_section): Call + Target::new_output_section. + (Layout::attach_allocated_section_to_segment): Put large section + sections in a separate load segment with the large segment flag + set. + (Layout::segment_precedes): Sort large data segments after other + load segments. + (align_file_offset): New static function. + (Layout::set_segment_offsets): Use align_file_offset. + * output.h (class Output_section): Add is_small_section_ and + is_large_section_ fields. + (Output_section::is_small_section): New function. + (Output_section::set_is_small_section): New function. + (Output_section::is_large_section): New function. + (Output_section::set_is_large_section): New function. + (Output_section::is_large_data_section): New function. + (class Output_segment): Add is_large_data_segment_ field. + (Output_segment::is_large_data_segment): New function. + (Output_segment::set_is_large_data_segment): New function. + * output.cc (Output_section::Output_section): Initialize new + fields. + (Output_segment::Output_segment): Likewise. + (Output_segment::add_output_section): Add assertion that large + data sections always go in large data segments. Force small data + sections to the end of the list of data sections. Force small BSS + sections to the start of the list of BSS sections. For large BSS + sections to the end of the list of BSS sections. + * symtab.h (class Symbol): Declare is_common_shndx. + (Symbol::is_defined): Check Symbol::is_common_shndx. + (Symbol::is_common): Likewise. + (class Symbol_table): Define enum Commons_section_type. Update + declarations. Add small_commons_ and large_commons_ fields. + * symtab.cc (Symbol::is_common_shndx): New function. + (Symbol_table::Symbol_table): Initialize new fields. + (Symbol_table::add_from_object): Put small and large common + symbols in the right list. + (Symbol_table::sized_finalized_symbol): Check + Symbol::is_common_shndx. + (Symbol_table::sized_write_globals): Likewise. + * common.cc (Symbol_table::do_allocate_commons): Allocate new + common symbol lists. Don't call do_allocate_commons_list if the + list is empty. + (Symbol_table::do_allocate_commons_list): Remove is_tls + parameter. Add comons_section_type parameter. Change all + callers. Handle small and large common symbols. + * object.cc (Sized_relobj::do_finalize_local_symbols): Check + Symbol::is_common_shndx. + * resolve.cc (symbol_to_bits): Likewise. + * target.h (Target::small_common_shndx): New function. + (Target::small_common_section_flags): New function. + (Target::large_common_shndx): New function. + (Target::large_common_section_flags): New function. + (Target::new_output_section): New function. + (Target::Target_info): Add small_common_shndx, large_common_shndx, + small_common_section_flags, and large_common_section_flags + fields. + (Target::do_new_output_section): New virtual function. + * arm.cc (Target_arm::arm_info): Initialize new fields. + * i386.cc (Target_i386::i386_info): Likewise. + * powerpc.cc (Target_powerpc::powerpc_info) [all versions]: + Likewise. + * sparc.c (Target_sparc::sparc_info) [all versions]: Likewise. + * x86_64.cc (Target_x86_64::x86_64_info): Likewise. + (Target_x86_64::do_new_output_section): New function. + * configure.ac: Define conditional MCMODEL_MEDIUM. + * testsuite/Makefile.am (check_PROGRAMS): Add large. + (large_SOURCES, large_CFLAGS, large_DEPENDENCIES): Define. + (large_LDFLAGS): Define. + * testsuite/large.c: New file. + * testsuite/testfile.cc (Target_test::test_target_info): + Initialize new fields. + * configure, testsuite/Makefile.in: Rebuild. + +2009-06-05 Doug Kwan + + * Makefile.am (CCFILES): Add target.cc. + * Makefile.in: Regenerate. + * i386.cc (class Target_i386): Define new virtual method to + override do_is_local_label_name in parent. + * object.cc (Sized_relobj::do_count_local_symbols): Discard + local symbols if --discard-locals or -X is given. + * options.h (class General_options): Declare new options + '--discard-locals' and '-X' for discarding locals. + * target.h (class Target): Define new methods is_local_label_name. + Declare new virtual method do_is_local_label_name. + * target.cc: New file. + * testsuite/Makefile.am (check_PROGRAMS): Add discard_locals_test. + (check_SCRIPTS): Add discard_locals_test.sh. + (check_DATA): Add discard_local_tests.syms. + (discard_locals_test_SOURCES, discard_locals_test_LDFLAGS): Define. + (discard_local_tests.syms, discard_locals_test.o): New make rules. + * testsuite/Makefile.in: Regenerate. + * testsuite/discard_locals_test.c: New file. + * testsuite/discard_locals_test.sh: Same. + +2009-06-05 Doug Kwan + + * object.cc (Sized_relobj::Sized_relobj): Initialize + discarded_eh_frame_shndx_ to -1U. + (Sized_relobj::do_layout): Record index of a discard .eh_frame + section. + (Sized_relobj::do_count_local_symbols): Skip local symbols in + a discarded .eh_frame section. + (Sized_relobj::do_finalize_local_symbols): Ditto. + * object.h (class Sized_relobj): Declare new member + discarded_eh_frame_shndx_. + * testsuite/Makefile.am (check_PROGRAMS): Add local_labels_test. + (local_labels_test.o, local_labels_test): New rules. + * testsuite/Makefile.in: Regenerate. + +2009-06-04 Doug Kwan + + * layout.cc (Layout::section_name_mapping): Add mapping for + special ARM sections. + +2009-06-03 Doug Kwan + + * arm.cc (utils::sign_extend): Reverse test in gold_assert. + (utils::has_overflow): Same. + +2009-06-03 Ian Lance Taylor + + * layout.cc (Layout::section_name_mapping): New array, replacing + Layout::linkonce_mapping. + (Layout::section_name_mapping_count): New variable, replacing + Layout::linkonce_mapping_count. + (Layout::linkonce_output_name): Remove. + (Layout::output_section_name): Rewrite. + * layout.h (class Layout): Rename Linkonce_mapping to + Section_name_mapping, linkonce_mapping to section_name_mapping, + linkonce_mapping_count to section_name_mapping_count. Don't + declare linkonce_output_name. + +2009-06-03 Doug Kwan + + * gold/arm.cc (namespace utils): New. + (Target_arm::reloc_is_non_pic): Define new method. + (class Arm_relocate_functions): New. + (Target_arm::Relocate::relocate): Handle relocation types used by + Android. + +2009-06-03 Ian Lance Taylor + + * arm.cc (Target_arm::scan::global): Use || instead of |. + +2009-06-02 Doug Kwan + + * gold/arm.cc (Target_arm::Scan::Scan): Initialize + issued_non_pic_error_. + (class Target_arm::Scan): Declare new method check_non_pic. + Define new method symbol_needs_plt_entry. + Declare new data member issued_non_pic_error_. + (class Target_arm::Relocate): Declare new method + should_apply_static_reloc. + (Target_arm::may_need_copy_reloc): Handle STT_ARM_TFUNC. + (Target_arm::Scan::check_non_pic): Define new method. + (Target_arm::Scan::local): Handle a small subset of reloc types used + by Android. + (Target_arm::Scan::local): Same. + (Target_arm::Relocate::should_apply_statci_reloc): Define new method. + +2009-05-31 Mikolaj Zalewski + + * incremental.cc (Incremental_inputs::report_command_line): Filter + out --incremental-* options. + +2009-05-29 Doug Kwan + + * gold/arm.cc (Output_data_plt_arm): Forward declaration for new + template class. + (class Target_arm): Update comment. + (Target_arm::Target_arm): Initialize new data members GOT_, + PLT_, GOT_PLT_, REL_DYN_, COPY_RELOCS_ and DYNBSS_. + Declare new methods Target_arm::got_section, Target_arm::make_plt_entry + and Target_arm::rel_dyn_section. + Declare new_enum Target_arm::Got_type. + Declare new data members GOT_, PLT_, GOT_PLT_, REL_DYN_, COPY_RELOCS_ + and DYNBSS_. + Update commments for member do_dynsym_value. + (Target_arm::got_size, Target_arm::plt_section, + Target_arm::may_need_copy_reloc and Target_arm::copy_reloc): Define + new methods inside class defintion. + (Target_arm::got_section): Define new method. + (Target_arm::rel_dyn_section): Same. + (Output_data_plt_arm): New template class. + (Output_data_plt_arm::Output_data_plt_arm): Define constructor. + (Output_data_plt_arm:do_adjust_output_section): Define new method. + (Output_data_plt_arm::add_entry): Same. + (Output_data_plt_arm::first_plt_entry): Define new + static data member for PLT instruction template. + (Output_data_plt_arm::plt_entry): Same. + (Output_data_plt_arm::do_write): Define new method. + (Target_arm::make_plt_entry): Same. + (Target_arm::do_finalize_sections): Same. + (Target_arm::do_dynsym_value): Same. + +2009-05-28 Doug Kwan + + * Makefile.am (TARGETSOURCES): Add arm.cc. + (ALL_TARGETOBJECTS): Add arm.$(OBJEXT) + * Makefile.in: Regenerate. + * arm.cc: New file. + * configure.tgt: Add armbe*-*-*, armeb*-*-* and arm*-*-* targets. + +2009-05-26 Doug Kwan + + * options.cc (General_options::parse_exclude_libs). Fix a comment. + (General_options::check_excluded_libs): Strip off directories in + archive name before matching like GNU ld does. + * testsuite/Makefile.am (MOSTLYCLEANFILES, + exclude_libs_test_DEPENDENCIES): Add alt/libexclude_libs_test_3.a + (exclude_libs_test_LDFLAGS): Add linker option + -Wl,--exclude-libs,libexclude_libs_test_3 + (exclude_libs_test_LADD): Add alt/libexclude_libs_test_3.a as + an explicit archive without using -l. + (alt/libexclude_libs_test_3.a): New make rule. + * testsuite/Makefile.in: Regenerate. + * testsuite/exclude_libs_test.c : Declare lib3_default(). + (main): Call it. + * exclude_libs_test.sh: Add tests for alt/exclude_libs_test_3.a. + * exclude_libs_test_3.c: New file. + +2009-05-26 Nick Clifton + + * po/id.po: New Indonesian translation. + * po/gold.pot: Updated template file. + +2009-05-22 Sriraman Tallam + + * testsuite/Makefile.am: Add -ffunction-sections to compile + gc_comdat_test files. Add -Wl,--gc-sections to build + gc_comdat_test. + * testsuite/Makefile.in: Regenerate. + * testsuite/gc_comdat_test.sh: Fix the condition around grep. + +2009-05-21 Sriraman Tallam + + * object.cc (Sized_relobj::map_to_kept_section): Return NULL if the + kept comdat section was garbage collected. + * testsuite/Makefile.am: Add test gc_comdat_test.sh. + * testsuite/Makefile.in: Regenerate. + * testsuite/gc_comdat_test.sh: New file. + * testsuite/gc_comdat_test_1.cc: New file. + * testsuite/gc_comdat_test_2.cc: New file. + +2009-05-19 Doug Kwan + + * archive.cc (Archive::Archive): Move constructor from archive.h + to here. Initialize no_export_. + (Archive::get_elf_object_for_member): Set no_export flag of object. + * archive.h (Archive::Archive): Move constructor body to + archive.cc. + (Archive::no_export): New method. + (Archive::no_export_): New field. + * object.h (Object::Object): Initialize no_export_ to false. + (Object::no_export, Object::set_no_export): New methods. + (Object::no_export_): New field. + * options.cc (General_options::parse_exclude_libs): New method. + (General_options::check_excluded_libs) Same. + * options.h (exclude_libs): New option. + (General_options::check_excluded_libs): New method declaration. + (General_options::excluded_libs_): New field. + * symtab.cc (Symbol_table::add_from_relobj): Hide symbols with + default or protected visibility if an object has no-export flag set. + testsuite/Makefile.am (check_PROGRAMS): Add exclude_libs_test. + (check_SCRIPTS): Add exclude_libs_test.sh. + (check_DATA): Add exclude_libs_test.syms. + (MOSTLYCLEANFILES): Add exclude_libs_test.syms, + libexclude_libs_test_1.a and libexclude_libs_test_2.a. + (exclude_libs_test_SOURCES, exclude_libs_test_DEPENDENCIES, + exclude_libs_test_LDFLAGS and exclude_libs_test_LDADD): Define. + (exclude_libs_test.syms, libexclude_libs_test_1.a, + libexclude_libs_test_2.a): New rules. + * testsuite/Makefile.in: Regenerate. + * testsuite/exclude_libs_test.c: New file. + * testsuite/exclude_libs_test.sh: Ditto. + * testsuite/exclude_libs_test_1.c: Ditto. + * testsuite/exclude_libs_test_2.c: Ditto. + +2009-05-15 Ian Lance Taylor + + * configure.ac: Check for declarations for cases where libiberty.h + checks HAVE_DECL_xxx. + * configure, config.in: Rebuild. + +2009-05-15 Mikolaj Zalewski + + * gold.h (Incremental_argument_list): Remove (invalid) forward + declaration. + * incremental.cc (Incremental_inputs::report_achive): New method. + (Incremental_inputs::report_object): New method. + (Incremental_inputs::report_script): New method. + (Incremental_inputs::finalize_inputs): New method. + (Incremental_inputs::finalize): Call finalize_inputs(). + (Incremental_inputs::sized_create_incremental_inputs_section_data): + Create inputs entries. + * incremental.h (Incremental_input_type): New enum. + (Incremental_inputs::Incremental_input): Initialize new fields. + (Incremental_inputs::report_inputs): New method. + (Incremental_inputs::report_achive): New method. + (Incremental_inputs::report_object): New method. + (Incremental_inputs::report_script): New method. + (Incremental_inputs::finalize_inputs): New method. + (Incremental_inputs::Input_info): New struct. + (Incremental_inputs::Input_info_map): New typedef. + (Incremental_inputs::lock_): New field. + (Incremental_inputs::Inputs_): New field. + (Incremental_inputs::Inputs_map): New field. + * main.cc (main): Call Incremental_input::report_inputs. + * options.h (Input_argument_list): Typedef moved from + Input_arguments. + (Input_file_group::Files): Remove, use ::Input_argument_list. + (Input_file_group::Input_argument_list): Remove, use + ::Input_argument_list. + * plugin.cc (Plugin_manager::add_input_file): Add error in + incremental build. + * read_syms.cc (do_read_syms): Call Incremental_input::report_* + functions. + * script.cc (read_input_script): Call + Incremental_input::report_script. + * script.h (Script_info): New class. + +2009-04-27 Ian Lance Taylor + + * x86_64.cc (do_adjust_output_section): Set entsize to + plt_entry_size. + +2009-04-23 Elliott Hughes + + * output.cc (Output_file::close): After short writes, continue + writing from the correct offset in the buffer being written. + +2009-04-23 Chris Demetriou + + * configure.ac (HAVE_TR1_UNORDERED_MAP_REHASH): New define. + * configure: Regenerate. + * config.in: Regenerate. + * gold.h: Avoid std::tr1::unordered_map and std::tr1::unordered_set + if HAVE_TR1_UNORDERED_MAP_REHASH is not defined. + +2009-04-21 Mikolaj Zalewski + + * incremental.cc (Incremental_inputs_header_data): Renamed from + Incremental_input_header_data. + (Incremental_inputs_header_data::data_size): New field. + (Incremental_inputs_header_data::put_input_file_count): Renamed + from input_file_count. + (Incremental_inputs_header_data::put_command_line_offset): Renamed + from command_line_offset. + (Incremental_inputs_header_data::put_reserved): Renamed from + put_reserved. + (Incremental_inputs_entry_data): Renamed from + Incremental_input_entry_data. + (Incremental_inputs_entry_data::data_size): New field. + (Incremental_inputs::report_command_line): New method. + (Incremental_inputs::finalize): New method. + (Incremental_inputs::create_incremental_inputs_data): New method. + (Incremental_inputs::sized_create_incremental_inputs_data): New method. + * incremental.h: New file. + * layout.cc (Layout::Layout): Handle new incremental_inputs_. + (Layout::finalize): Create incremental inputs section in + incremental builds. + (Layout::create_incremental_info_sections): New method. + * layout.h (Layout::incremental_inputs): New method. + (Layout::create_incremental_info_sections): New method. + (Layout::incremental_inputs_): New field. + * main.cc (main): Notify Incremental_input of the command line. + +2009-04-01 Ian Lance Taylor + Mikolaj Zalewski + + * gold.h (reserve_unordered_map): Define, three versions, one for + each version of Unordered_map. + * layout.cc (Layout::Layout): Remove options parameter. Add + number_of_input_files parameter. Don't initialize options_. + Initialize number_of_input_files_ and resized_signatures_. Move + sections_are_attached_. + (Layout::layout_group): Reserve space for group_signatures_. + (Layout::find_or_add_kept_section): Change name parameter to be a + reference. Resize signatures_ map when it gets large enough. + (Layout::layout_eh_frame): Use parameters->options() instead of + this->options_. + (Layout::make_output_section): Likewise. + (Layout::attach_allocated_section_to_segment): Likewise. + (Layout::finalize, Layout::create_executable_stack): Likewise. + (Layout::set_segment_offsets, Layout::create_interp): Likewise. + (Layout::finish_dynamic_section, Layout::write_binary): Likewise. + * layout.h (class Layout): Update declarations. Remove options_ + field. Add number_of_input_files_ and resized_signatures_ + fields. Move sections_are_attached_ field. + * main.cc (main): Pass number of input files to Layout + constructor. Don't pass options. + +2009-03-30 Ian Lance Taylor + + * ffsll.c (ffsll): Correct implementation. + +2009-03-27 Ian Lance Taylor + + * ffsll.c: New file. + * configure.ac: Call AC_REPLACE_FUNCS on ffsll. + * gold.h (ffsll): Declare if HAVE_FFSLL is not defined. + * ftruncate.c (ftruncate): Declare before definition. + * mremap.c (mremap): Likewise. + * pread.c (pread): Likewise. + * configure, Makefile.in, config.in: Rebuild. + + * mremap.c: New file. + * configure.ac: Call AC_REPLACE_FUNCS on mremap. + * gold.h (MREMAP_MAYMOVE): Define if HAVE_MREMAP is not defined. + (mremap): Declare if HAVE_MREMAP is not defined. + * configure, Makefile.in, config.in: Rebuild. + +2009-03-27 Cary Coutant + + * powerpc.cc (Target_powerpc::check_non_pic): Assert that output is + position independent. + * sparc.cc (Target_sparc::check_non_pic): Likewise. + * x86_64.cc (Target_x86_64::check_non_pic): Likewise. + +2009-03-24 Cary Coutant + + * symtab.h (needs_plt_entry): Check for unsatisfied reference from + an executable. + (needs_dynamic_reloc): Likewise. + +2009-03-24 Ian Lance Taylor + + * yyscript.y (file_cmd): Recognize EXTERN. + (extern_name_list, extern_name_list_body): New nonterminals. + * script.cc (script_add_extern): Define. + * script-c.h (script_add_extern): Declare. + +2009-03-24 Rafael Avila de Espindola + + * object.cc (is_elf_object): Define. + * object.h (is_elf_object): Declare. + * archive.cc (Archive::get_elf_object_for_member): Call + is_elf_object. + * readsyms.cc (Read_symbols::do_read_symbols): Likewise. + +2009-03-24 Elliott Hughes + + * output.cc (Output_file::map_anonymous): Define. + (Output_file::map): Use map_anonymous. If the regular mmap fails, + try an anonymous one. Report the size if the mmap fails. + * output.h (class Output_file): Declare map_anonymous. + +2009-03-24 Ian Lance Taylor + + * target-select.cc (instantiate_target): Don't acquire the lock if + the instantiated_target_ field has already been set. + +2009-03-23 Ian Lance Taylor + + * gold-threads.h (class Initialize_lock): Define. + * gold-threads.cc (class Initialize_lock_once): Define. + (initialize_lock_control): New static variable. + (initialize_lock_pointer): New static variable. + (initialize_lock_once): New static function. + (Initialize_lock::Initialize_lock): Define. + (Initialize_lock::initialize): Define. + * target-select.h: Include "gold-threads.h". + (class Target_selector): Add lock_ and initialize_lock_ fields. + Don't define instantiate_target, just declare it. + * target-select.cc (Target_selector::Target_selector): Initialize + new fields. + (Target_selector::instantiate_target): Define. + * descriptors.h: Include "gold-threads.h". + (class Descriptors): Add initialize_lock_ field. + * descriptors.cc (Descriptors::Descriptors): Initialize new + field. + (Descriptors::open): Use initialize_lock_ field + * errors.h (class Errors): Add initialize_lock_ field. + * errors.cc (Errors::Errors): Initialize new field. + (Errors::initialize_lock): Use initialize_lock_ field. + * powerpc.cc (class Target_selector_powerpc): Remove + instantiated_target_ field. In do_recognize call + instantiate_target rather than do_instantiate_target. In + do_instantiate_target just allocate a new target. + * sparc.cc (class Target_selector_sparc): Likewise. + + * freebsd.h: New file. + * i386.cc: Include "freebsd.h". + (Target_i386): Derive from Target_freebsd rather than + Sized_target. + (Target_selector_i386): Derive from Target_selector_freebsd rather + than Target_selector. + * x86_64.cc: Include "freebsd.h". + (Target_x86_64): Derive from Target_freebsd rather than + Sized_target. + (Target_selector_x86_64): Derive from Target_selector_freebsd + rather than Target_selector. + * target.h (class Target): Add adjust_elf_header and + do_adjust_elf_header. + * output.cc (Output_file_header:: do_sized_write): Call target + adjust_elf_header routine. + * configure.tgt: Set targ_osabi. + * configure.ac: Define GOLD_DEFAULT_OSABI. + * parameters.cc (Parameters::default_target): Pass + GOLD_DEFAULT_OSABI to select_target. + * target-select.h (class Target_selector): Make instantiate_target + protected rather than private. + * Makefile.am (HFILES): Add freebsd.h. + * configure, Makefile.in, config.in: Rebuild. + + * merge.cc (do_add_input_section): Correct pend value. Change + message about last entry not being null terminated from error to + warning. + +2009-03-20 Mikolaj Zalewski + + * incremental.cc: New file. + * Makefile.am (CCFILES): Add incremental.cc. + * Makefile.in: Rebuild. + +2009-03-19 Paul Pluzhnikov + + * layout.cc (Layout::output_section_name): Preserve names + of '.note.' sections. + +2009-03-19 Ian Lance Taylor + + * descriptors.cc (Descriptors::open): Check that the options are + valid before using them. + +2009-03-18 Ian Lance Taylor + + * script-sections.h: Include . + (class Script_sections): Change Sections_elements from std::vector + to std::list. Typedef public Elements_iterator. Add + orphan_section_placement_, data_segment_align_start_, and + saw_data_segment_align_ fields. Remove data_segment_align_index_ + field. + * script-sections.cc (class Orphan_section_placement): New class. + (class Sections_element): Add virtual functions is_relro and + orphan_section_init. Remove virtual function place_orphan_here. + (class Output_section_definition): Add is_relro and + orphan_section_init. Remove place_orphan_here. + (class Orphan_output_section): Likewise. + (Script_sections::Script_sections): Update for field changes. + (Script_sections::data_segment_align): Set saw_data_segment_align_ + and data_segment_align_start_, not data_segment_align_index. + (Script_sections::data_segment_relro_end): Check + saw_data_segment_align_. Use data_segment_align_start_ rather + than data_segment_align_index_. + (Script_sections::place_orphan): Rewrite to use + Orphan_section_placement. + +2009-03-17 Ian Lance Taylor + + * archive.cc (Archive::add_symbols): Check for a version attached + to the symbol name in the archive map. + * testsuite/Makefile.am (check_PROGRAMS): Add ver_test_11. + (ver_test_11_SOURCES, ver_test_11_DEPENDENCIES): Define. + (ver_test_11_LDFLAGS, ver_test_11_LDADD): Define. + (ver_test_11.a): New target. + * testsuite/Makefile.in: Rebuild. + + * configure.ac: Check for chsize and posix_fallocate. Replace + ftruncate. + * ftruncate.c: New file, from gnulib. + * output.cc (posix_fallocate): Define dummy version if not + HAVE_POSIX_FALLOCATE. + (Output_file::map): Call posix_fallocate rather than lseek and + write. + * gold.h (ftruncate): Declare if not HAVE_FTRUNCATE. + * configure, Makefile.in, config.in: Rebuild. + +2009-03-17 Paul Pluzhnikov + + * layout.h (Layout::create_note): Add section_name parameter. + * layout.cc (Layout::create_note): Likewise. + (Layout::create_build_id, Layout::create_gold_note): Fix callers. + +2009-03-17 Ian Lance Taylor + + * descriptors.cc: Include "options.h". + (FD_CLOEXEC, O_CLOEXEC): Define if not defined. + (Descriptors::open): Always use O_CLOEXEC when opening a new + descriptor. If we have a plugin, and O_CLOEXEC was not defined, + then set FD_CLOEXEC. + + * sparc.cc (class Target_sparc): Add has_got_section. + (Target_sparc::Scan::global): If we see _GLOBAL_OFFSET_TABLE_, + make sure we have a GOT section. + + * sparc.cc (optimize_tls_reloc): Recognize R_SPARC_TLS_IE_ADD. + (Target_sparc::Scan::local): Likewise. + (Target_sparc::Scan::global): Likewise. + (Target_sparc::Relocate::relocate): Likewise. + (Target_sparc::Relocate::relocate_tls): Likewise. + + * symtab.cc (Symbol_table::define_default_version): New function, + broken out of add_from_object. + (Symbol_table::add_from_object): Call define_default_version. + (Symbol_table::define_special_symbol): Add resolve_oldsym + parameter. Change all callers. If the version for a symbol comes + from a version script, resolve it with the symbol with the same + name with no version. Also add the symbol without a version if + appropriate. + (do_define_in_output_data): If resolving with oldsym, don't delete + sym. + (do_define_in_output_segment): Likewise. + (do_define_as_constant): Likewise. + * symtab.h (class Symbol_table): Update declarations. + +2009-03-13 Ian Lance Taylor + + * readsyms.cc (Read_symbols::incompatible_warning): New function. + (Read_symbols::requeue): New function. + (Read_symbols::do_read_symbols): If make_elf_object fails because + the target type is not configured, and the file was searched for, + issue a warning and retry with the next directory. + (Add_symbols::run): If the file has an incompatible format, and + it was searched for, requeue the Read_symbols task. On error, + release the object. + * readsyms.h (class Read_symbols): Add dirindex_ field. Add + dirindex parameter to constructor. Change all callers. Declare + incompatible_warning and requeue. + (class Add_symbols): Add dirpath_, dirindex_, mapfile_, + input_argument_ and input_group_ fields. Add them to + constructor. Change all callers. + (class Read_script): Add dirindex_ field. Add it to constructor. + Change all callers. + * archive.cc (Archive::setup): Remove input_objects parameter. + Change all callers. + (Archive::get_file_and_offset): Likewise. + (Archive::read_all_symbols): Likewise. + (Archive::read_symbols): Likewise. + (Archive::get_elf_object_for_member): Remove input_objects + parameter. Add punconfigured parameter. Change all callers. + (Archive::add_symbols): Change return type to bool. Check return + value of include_member. + (Archive::include_all_members): Likewise. + (Archive::include_member): Change return type to bool. Return + false if first included object has incompatible target. Set + included_member_ field. + (Add_archive_symbols::run): If add_symbols returns false, requeue + Read_symbols task. + * archive.h (class Archive): Add included_member_ field. + Initialize it in constructor. Add input_file and searched_for + methods. Update declarations. + (class Add_archive_symbols): Add dirpath_, dirindex_, and + input_argument_ fields. Add them to constructor. Change all + callers. + * script.cc: Include "target-select.h". + (class Parser_closure): Add skip_on_incompatible_target_ and + found_incompatible_target_ fields. Add + skip_on_incompatible_target parameter to constructor. Change all + callers. Add methods skip_on_incompatible_target, + clear_skip_on_incompatible_target, found_incompatible_target, and + set_found_incompatible_target. + (read_input_script): Add dirindex parameter. Change all callers. + If parser finds an incompatible target, requeue Read_symbols + task. + (script_set_symbol): Clear skip_on_incompatible_target in + closure. + (script_add_assertion, script_parse_option): Likewise. + (script_start_sections, script_add_phdr): Likewise. + (script_check_output_format): New function. + * script.h (read_input_script): Update declaration. + * script-c.h (script_check_output_format): Declare. + * yyscript.y (file_cmd): Handle OUTPUT_FORMAT. + (ignore_cmd): Remove OUTPUT_FORMAT. + * fileread.cc (Input_file::Input_file): Add explicit this. + (Input_file::will_search_for): New function. + (Input_file::open): Add pindex parameter. Change all callers. + * fileread.h (class Input_file): Add input_file_argument method. + Declare will_search_for. Update declarations. + * object.cc (make_elf_object): Add punconfigured parameter. + Change all callers. + * object.h (class Object): Make input_file public. Add + searched_for method. + (make_elf_object): Update declaration. + * dirsearch.cc (Dirsearch::find): Add pindex parameter. Use it to + restart search. + * dirsearch.h (class Dirsearch): Update declaration. + * options.h (class General_options): Add --warn-search-mismatch. + * parameters.cc (Parameters::is_compatible_target): New function. + * parameters.h (class Parameters): Declare is_compatible_target. + * workqueue.cc (Workqueue::add_blocker): New function. + * workqueue.h (class Workqueue): Declare add_blocker. + + * fileread.cc (Input_file::open): Remove options parameter. + Change all callers. + (Input_file::open_binary): Likewise. + * script.cc (read_input_script): Likewise. + * readsyms.h (class Read_symbols): Remove options_ field. Remove + options parameter from constructor. Change all callers. + (class Read_script): Likewise. + * fileread.h (class Input_file): Update declarations. + * script.h (read_input_script): Update declaration. + +2009-03-10 Nick Clifton + + * po/es.po: New Spanish translation. + +2009-03-06 Cary Coutant + + * options.cc (parse_short_option): Keep dash_z from registering itself. + +2009-03-03 Ian Lance Taylor + + PR 9918 + * target-reloc.h (relocate_section): Pass output_section to + relocate. + * i386.cc (Target_i386::should_apply_static_reloc): Add + output_section parameter. Change all callers. + (Target_i386::Relocate::relocate): Add output_section parameter. + * x86_64.cc (Target_x86_64::Relocate::relocate): Likewise. + * sparc.cc (Target_sparc::Relocate::relocate): Likewise. + * powerpc.cc (Target_powerpc::Relocate::relocate): Likewise. + * testsuite/two_file_shared.sh: New script. + * testsuite/Makefile.am (check_SCRIPTS): Add two_file_shared.sh. + (check_DATA): Add two_file_shared.dbg. + (two_file_shared.dbg): New target. + * testsuite/Makefile.in: Rebuild. + +2009-03-01 Ian Lance Taylor + + * configure.ac: Check for byteswap.h. + * configure: Rebuild. + * config.in: Rebuild. + +2009-03-01 Mikolaj Zalewski + + * layout.cc (Layout::find_or_add_kept_section): New function. + (Layout::add_comdat): Removed. + * layout.h (struct Kept_section): Move out of class Layout. + Remove trailing underscores from field names. Add group_sections + field. Rename group_ field to is_group. Change all uses. + (class Layout): Declare find_or_add_kept_section, not add_comdat. + * object.cc (Sized_relobj::Sized_relobj): Don't initialize + comdat_groups_ field. + (Sized_relobj::include_section_group): Use + find_or_add_kept_section and Kept_section::group_sections. + (Sized_relobj::include_linkonce_section): Likewise. + * object.cc (class Sized_relobj): Don't define Comdat_group or + Comdat_group_table. Remove find_comdat_group and + add_comdat_group. Remove comdat_groups_ field. + * plugin.cc (include_comdat_group): Use + Layout::find_or_add_kept_section. + +2009-02-28 Ian Lance Taylor + + * README: --gc-sections and map files are now supported. Document + some build requirements. + + PR 6992 + * symtab.cc (Symbol_table::sized_write_section_symbol): In a + relocatable link set the value of the section symbol to zero. + * object.cc (Sized_relobj::do_finalize_local_symbols): In a + relocatable link don't include the section address in the local + symbol value. + +2009-02-27 Ian Lance Taylor + + PR 6811 + * options.h (class Search_directory): Add is_system_directory. + (class General_options): Declare is_in_system_directory. + * options.cc (get_relative_sysroot): Make static. + (get_default_sysroot): Make static. + (General_optoins::is_in_system_directory): New function. + * fileread.cc (Input_file::is_in_system_directory): New function. + * fileread.h (class Input_file): Declare is_in_system_directory. + * object.h (class Object): Add is_in_system_directory. + (class Input_objects): Remove system_library_directory_ field. + * object.cc (Input_objects::add_object): Don't set + system_library_directory_. + (input_objects::found_in_system_library_directory): Remove. + * symtab.cc (Symbol_table::write_globals): Remove input_objects + parameter. Change all callers. + (Symbol_table::sized_write_globals): Likewise. + (Symbol_table::warn_about_undefined_dynobj_symbol): Likewise. + Call Object::is_in_system_directory. + * symtab.h (class Symbol_table): Update declarations. + + PR 5990 + * descriptors.h (Open_descriptor): Add is_on_stack field. + * descriptors.cc (Descriptors::open): If the descriptor is on the + top of the stack, remove it. Initialize is_on_stack field. + (Descriptors::release): Only add pod to stack if it is not on the + stack already. + (Descriptors::close_some_descriptor): Clear stack_next and + is_on_stack fields. + + PR 7091 + * output.cc (Output_section::find_starting_output_address): Rename + from starting_output_address; add PADDR parameter; change return + type. + * output.h (class Output_section): Declare + find_starting_output_address instead of starting_output_address. + * object.cc (Sized_relobj::do_finalize_local_symbols): Handle a + section symbol for which we can't find a merge section. + + PR 9836 + * symtab.cc (Symbol_table::add_from_object): If the visibility is + hidden or internal, force the symbol to be local. + * resolve.cc (Symbol::override_visibility): Define. + (Symbol::override_base): Use override_visibility. + (Symbol_table::resolve): Likewise. + (Symbol::override_base_with_special): Likewise. + (Symbol_table::override_with_special): If the visibility is hidden + or internal, force the symbol to be local. + * symtab.h (class Symbol): Add set_visibility and + override_visibility. + * testsuite/ver_test_1.sh: New file. + * testsuite/Makefile.am (check_SCRIPTS): Add ver_test_1.sh. + (check_DATA): Add ver_test_1.syms. + (ver_test_1.syms): New target. + * testsuite/Makefile.in: Rebuild. + +2009-02-25 Cary Coutant + + * layout.cc (Layout::choose_output_section): Don't rename sections + when using a linker script that has a SECTIONS clause. + * Makefile.in: Regenerate. + + * testsuite/Makefile.am (script_test_5.sh): New test case. + * testsuite/Makefile.in: Regenerate. + * testsuite/script_test_5.cc: New file. + * testsuite/script_test_5.sh: New file. + * testsuite/script_test_5.t: New file. + +2009-02-13 Rafael Avila de Espindola + + * archive.cc (Archive::include_member): Update calls to add_symbols. + * dynobj.cc (Sized_dynobj::make_version_map): Add + the Layout argument. + * dynobj.h (do_add_symbols): Add the Layout argument. + * object.cc (Sized_relobj::do_add_symbols): Add the + Layout argument. + * object.h (Object::add_symbols): Add the Layout argument. + (Object::do_add_symbols): Add the Layout argument. + (Sized_relobj::do_add_symbols): Add the Layout argument. + * plugin.cc (Sized_pluginobj::do_add_symbols): + Unify the two versions. + (Add_plugin_symbols): Remove. + * plugin.h (Pluginobj::add_symbols, Pluginobj::do_add_symbols): Remove. + (Sized_pluginobj::do_add_symbols): Unify the two versions. + (Add_plugin_symbols): Remove. + * readsyms.cc (Read_symbols::do_read_symbols): Update call to + Add_symbols. Use Add_symbols instead of Add_plugin_symbols. + (Add_symbols::run): Make it work with Pulginobj. + +2009-02-06 Ian Lance Taylor + + * object.cc (Sized_relobj::do_layout): Make info message start + with lower case letter. + +2009-02-06 Mikolaj Zalewski + + * binary.cc: Fix file comment. + + * options.h (enum Incremental_disposition): Define. + (class General_options): Add new options: --incremental, + --incremental_changed, --incremental_unchanged, + --incremental_unknown. Add incremental_disposition_ and + implicit_incremental_ fields. + (General_options::incremental_disposition): New function. + (class Position_dependent_options): Add incremental_disposition + option. + (Position_dependent_options::copy_from_options): Set incremental + 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 + incremental_disposition_ and implicit_incremental_. + (General_options::finalize): Check for uasge of --incremental-* + without --incremental. + +2009-02-06 Chris Demetriou + + * gold.h (gold_undefined_symbol): Change to take only a Symbol + pointer and to report location as the file name associated with + the symbol. + (gold_undefined_symbol_at_location): New function to replace the + old gold_undefined_symbol functionality. + * target-reloc.h (relocate_section): Update to use + gold_undefined_symbol_at_location. + * symtab.cc (Symbol_table::warn_about_undefined_dynobj_symbol): + Call gold_undefined_symbol function rather than gold_error. + * errors.h (Errors::undefined_symbol): Take location as a + string, rather than calculating it from a relocation. + * errors.cc (Errors::fatal): Print "fatal error:" before the + formatted message. + (Errors::error, Errors::error_at_location): Print "error: " + before the formatted message. + (Errors::undefined_symbol): Take location as a string, rather + than calculating it from a relocation. + (gold_undefined_symbol_at_location): New function akin to + old gold_undefined_symbol, calculates location from relocation. + (gold_undefined_symbol): Change to take only a Symbol pointer + and to report location as the file name associated with the symbol. + * testsuite/debug_msg.sh: Update for changed error messages. + * testsuite/undef_symbol.sh: Likewise. + +2009-02-04 Duncan Sands + + PR 9812 + * reduced_debug_output.h + (Output_reduced_debug_abbrev_section::failed): Use format for + gold_warning. + (Output_reduced_debug_info_section::faild): Likewise. + +2009-01-31 Mikolaj Zalewski + + * script.cc (Lazy_demangler): New class. + (Version_script_info::get_symbol_version_helper): Demangle a + symbol only once. + +2009-01-29 Cary Coutant + + * i386.cc (Target_i386::Relocate::relocate): Recognize non-PIC calls + to __tls_get_addr. + * x86_64.cc (Target_x86_64::Relocate::relocate): Likewise. + +2009-01-28 Ian Lance Taylor + + * version.cc (version_string): Bump to 1.9. + + * gold.h: Include and . + * version.cc: Include . + * object.cc (Sized_relobj::do_layout): Initialize gc_sd to avoid a + warning. + * reduced_debug_output.cc (insert_into_vector): Rename from + Insert_into_vector; change all callers. Use Swap_unaligned to + avoid aliasing issue; remove union since it is unnecessary. + +2009-01-27 Sriraman Tallam + + * Makefile.am (CCFILES): Add gc.cc. + (HFILES): Add gc.h. + * Makefile.in: Regenerate. + * gold.cc (Gc_runner): New class. + (queue_initial_tasks): Call garbage collection related tasks + when corresponding options are invoked. + (queue_middle_gc_tasks): New function. + (queue_middle_tasks): Reorder tasks to allow relocs to be read and + processed early before laying out sections during garbage collection. + * gold.h (queue_middle_gc_tasks): New function. + (is_prefix_of): Move from "layout.cc". + * i386.cc (Target_i386::gc_process_relocs): New function. + * layout.cc (is_prefix_of): Remove. Move to "gold.h" + * main.cc (main): Create object of class "Garbage_collection". + * object.cc (Relobj::copy_symbols_data): New function. + (Relobj::is_section_name_included): New function. + (Sized_relobj::do_layout): Allow this function to be called twice + during garbage collection and defer layout of section during the + first call. + * object.h (Relobj::get_symbols_data): New function. + (Relobj::is_section_name_included): New function. + (Relobj::copy_symbols_data): New function. + (Relobj::set_symbols_data): New function. + (Relobj::get_relocs_data): New function. + (Relobj::set_relocs_data): New function. + (Relobj::is_output_section_offset_invalid): New pure virtual function. + (Relobj::gc_process_relocs): New function. + (Relobj::do_gc_process_relocs): New pure virtual function. + (Relobj::sd_): New data member. + (Sized_relobj::is_output_section_offset_invalid): New function. + (Sized_relobj::do_gc_process_relocs): New function. + * options.h (General_options::gc_sections): Modify to not be a no-op. + (General_options::print_gc_sections): New option. + * plugin.cc (Plugin_finish::run): Remove function call to + Plugin_manager::layout_deferred_objects. Move it to "gold.cc". + * powerpc.cc (Target_powerpc::gc_process_relocs): New function. + * reloc.cc (Read_relocs::run): Add task to process relocs and + determine unreferenced sections when doing garbage collection. + (Gc_process_relocs): New class. + (Sized_relobj::do_gc_process_relocs): New function. + (Sized_relobj::do_scan_relocs): Don't try to scan the relocs for + sections that are garbage collected. + * reloc.h (Gc_process_relocs): New class. + * sparc.cc (Target_sparc::gc_process_relocs): New function. + * symtab.cc (Symbol::should_add_dynsym_entry): Do not add entries for + symbols whose corresponding sections are garbage collected. + (Symbol_table::Symbol_table): Add new parameter for the garbage + collection object. + (Symbol_table::gc_mark_undef_symbols): New function. + (Symbol_table::gc_mark_symbol_for_shlib): New function. + (Symbol_table::gc_mark_dyn_syms): New function. + (Symbol_table::resolve): Do not treat symbols seen in dynamic objects + as garbage. + (Symbol_table::add_from_object): Likewise. + (Symbol_table::add_from_relobj): When building shared objects, do not + treat externally visible symbols as garbage. + (Symbol_table::sized_finalize_symbol): Do not check dynamic symbol + table information for static and relocatable links. + * symtab.h (Symbol_table::set_gc): New function. + (Symbol_table::gc): New function. + (Symbol_table::gc_mark_undef_symbols): New function. + (Symbol_table::gc_mark_symbol_for_shlib): New function. + (Symbol_table::gc_mark_dyn_syms): New function. + (Symbol_table::gc_): New data member. + * target.h (Sized_target::gc_process_relocs): New pure virtual + function. + * x86_64.cc (Target_x86_64::gc_process_relocs): New function. + * testsuite/testfile.cc (Target_test::gc_process_relocs): New function. + +2009-01-20 Chris Faylor + + * options.h (General_options::gc_sections): Define as a no-op for now. + (General_options::no_keep_memory): Ditto. + (General_options::Bshareable): Define. + * options.cc (General_options::finalize): Honor -Bshareable. + +2009-01-20 Andreas Schwab + + * powerpc.cc (Powerpc_relocate_functions::rel16_ha): Don't try to + read the value in the contents, since we don't use it. Use the + template endianness when writing. + (Relocate::relocate): Use it for R_PPC_REL16_HA. + +2009-01-19 Andreas Schwab + + * configure.tgt (powerpc64-*): Fix targ_obj. + +2009-01-15 Ian Lance Taylor + + * object.cc (Sized_relobj::write_local_symbols): Don't write out + local symbols when stripping all symbols. + +2009-01-14 Cary Coutant + + * output.cc (Output_reloc): Add explicit instantiations. + +2009-01-14 Cary Coutant + + * archive.cc (Archive::get_elf_object_for_member): Remove call + to File_read::claim_for_plugin. + * descriptors.cc (Descriptors::open): Remove reference to + is_claimed. + (Descriptors::claim_for_plugin): Remove. + * descriptors.h (Descriptors::claim_for_plugin): Remove. + (Descriptors::is_claimed): Remove. + (claim_descriptor_for_plugin): Remove. + * fileread.cc (File_read::claim_for_plugin): Remove. + * fileread.h (File_read::claim_for_plugin): Remove. + (File_read::descriptor): Reopen descriptor if necessary. + * plugin.cc (Plugin::load): Add two new APIs to transfer vector. + (Plugin_manager::all_symbols_read): Add task parameter. Change + all callers. + (Plugin_manager::get_input_file): New function. + (Plugin_manager::release_input_file): New function. + (Pluginobj::Pluginobj): Add filesize parameter and initialize + corresponding data member. + (Sized_pluginobj::Sized_pluginobj): Add filesize parameter + and pass to base constructor. Change all callers. + (get_input_file, release_input_file): New functions. + (make_sized_plugin_object): Add filesize parameter. Change all callers. + * plugin.h (Plugin_manager::Plugin_manager): Initialize task_ member. + (Plugin_manager::all_symbols_read): Add task parameter. + (Plugin_manager::get_input_file): New function. + (Plugin_manager::release_input_file): New function. + (Plugin_manager::task_): New data member. + (Pluginobj::Pluginobj): Add filesize parameter. + (Pluginobj::filename): New function. + (Pluginobj::descriptor): New function. + (Pluginobj::filesize): New function. + (Pluginobj::filesize_): New data member. + (Sized_pluginobj::Sized_pluginobj): Add filesize parameter. + * readsyms.cc (Read_symbols::do_read_symbols): Remove call to + File_read::claim_for_plugin; use Object::unlock to unlock the file. + + * testsuite/Makefile.am (plugin_test_4): New test case for plugins + with archive libraries. + * testsuite/Makefile.in: Regenerate. + * testsuite/plugin_test.c (struct sym_info): New type. + (get_input_file, release_input_file): New static variables. + (onload): Capture new transfer vector entries. + (claim_file_hook): Stop reading at end of file according to filesize. + Factor out parsing of readelf output into separate function. + (all_symbols_read_hook): Exercise get_input_file and release_input_file + APIs and get the source file name from the symbol table. Convert + source file name to corresponding object file name. Print info + message when adding new input files. + (parse_readelf_line): New function. + * testsuite/plugin_test_1.sh: Add checks for new info messages. + * testsuite/plugin_test_2.sh: Likewise. + * testsuite/plugin_test_3.sh: Likewise. + * testsuite/plugin_test_4.sh: New test case. + +2009-01-07 Ian Lance Taylor + + * version.cc (version_string): Bump to 1.8. + +2008-12-23 Cary Coutant + + * gold.cc (gold_exit): Call plugin cleanup handlers on exit. + * plugin.cc (Plugin_manager::finish): Rename as + layout_deferred_objects. Move cleanup to separate function. + (Plugin_manager::cleanup): New function. + (Plugin_finish::run): Call layout_deferred_objects and cleanup + separately. + * plugin.h (Plugin_manager::finish): Rename as + layout_deferred_objects. + (Plugin_manager::cleanup): New function. + (Plugin_manager::cleanup_done): New field. + +2008-12-23 Cary Coutant + + * plugin.cc (is_visible_from_outside): New function. + (Pluginobj::get_symbol_resolution_info): Call is_visible_from_outside + so we don't return "IR only" status for exported symbols or -r links. + + * testsuite/Makefile.am (plugin_test_3): New test case. + * testsuite/Makefile.in: Regenerate. + * testsuite/plugin_test_3.sh: New file. + +2008-12-22 Cary Coutant + + * object.cc (Sized_relobj::layout_section): New function. + (Sized_relobj::do_layout): Defer layout of input sections until after + plugin has provided replacement files. + (Sized_relobj::do_layout_deferred_sections): New function. + * object.h (Relobj::set_section_offset): Remove virtual keyword. + (Relobj::layout_deferred_sections): New function. + (Relobj::do_layout_deferred_sections): New function. + (Sized_relobj::do_layout_deferred_sections): New function. + (Sized_relobj::layout_section): New function. + (Sized_relobj::Deferred_layout): New structure. + (Sized_relobj::deferred_layout_): New field. + * plugin.cc (Plugin_manager::finish): Renamed, was cleanup. + Change all callers. Layout deferred sections. + (class Plugin_finish): Renamed, was Plugin_cleanup. Change all + references. + (Plugin_hook::run): Move code from do_plugin_hook inline. + (Plugin_hook::do_plugin_hook): Remove. + * plugin.h (Plugin_manager::Plugin_manager): Add missing initializers. + (Plugin_manager::finish): Renamed, was cleanup. + (Plugin_manager::should_defer_layout): New function. + (Plugin_manager::add_deferred_layout_object): New function. + (Plugin_manager::Deferred_layout_list): New type. + (Plugin_manager::deferred_layout_objects_): New field. + (Plugin_hook::do_plugin_hook): Remove. + +2008-12-17 Ian Lance Taylor + + * options.h (class General_options): Add --no case for + --export-dynamic. + +2008-12-16 Cary Coutant + + * plugin.cc (Plugin::load): Move LDPT_MESSAGE to front of transfer + vector. + (Plugin_manager::claim_file): Create plugin object even if + plugin did not call the add_symbols callback. + (Plugin_obj::get_symbol_resolution_info): Guard against plugin + asking for more symbols than were added. + * testsuite/Makefile.am (plugin_test_1): Add test case with + no global symbols. + (empty.syms): New target. + * testsuite/Makefile.in: Regenerate. + * testsuite/plugin_test.c (claim_file_hook): Add new debug + message. Don't call add_symbols if no globals. + (all_symbols_read_hook): Don't provide replacement for empty + claimed file. + +2008-12-12 Ian Lance Taylor + + * target-reloc.h (Default_scan_relocatable_relocs): Only discard + r_type == 0 for a local symbol with r_sym == 0. + (scan_relocatable_relocs): Pass r_sym to + local_non_section_strategy. + * reloc.cc (Emit_relocs_strategy::local_non_section_strategy): Add + r_sym parameter. + + * configure.ac: Update test for TLS descriptors: they are + supported as of glibc 2.9. + * configure: Rebuild. + +2008-12-11 Ian Lance Taylor + + PR 7091 + * target-reloc.h (Default_scan_relocatable_relocs): For each + function, map r_type == 0 to RELOC_DISCARD. + +2008-12-10 Cary Coutant + + * layout.cc (Layout::add_comdat): Allow COMDAT group from a replacement + object to override a kept COMDAT group from a plugin object. + +2008-12-09 Ian Lance Taylor + + PR 7088 + * yyscript.y (file_cmd): Handle INPUT. + + * testsuite/initpri1.c: Change all declarations to be full + prototypes by adding void, to avoid compiler warnings. + +2008-12-05 Rafael Avila de Espindola + + * options.cc (General_options::parse_plugin_opt): New. + (General_options::add_plugin): The argument now is just the filename. + (General_options::add_plugin_option): New. + * options.h (plugin_opt): New. + (add_plugin): Change argument name. + (add_plugin_option): New. + * plugin.cc (Plugin::load): Don't parse the plugin option. + * plugin.h (Plugin::Plugin): Rename argument. Init filename_. + (Plugin::add_option): New. + (Plugin::args_): Change type. + (Plugin::filename_): New. + (Plugin_manager::add_plugin_option): New. + * testsuite/Makefile.am (plugin_test_1): Use new syntax. + * testsuite/Makefile.in: Regenerate. + +2008-12-05 Cary Coutant + + * layout.cc (Layout::include_section): Check for SHF_EXCLUDE. + Handle --strip-lto-sections option. + * options.h (strip_lto_sections): New option. + +2008-12-01 Cary Coutant + + * plugin.cc (ld_plugin_message): Change format parameter to const. + Fix mismatch between new[] and delete. + +2008-11-14 Cary Coutant + + * reloc.cc (Sized_relobj::do_read_relocs): Use constant invalid_address + instead of -1U. + +2008-11-05 Craig Silverstein + + * options.cc (General_options::parse_dynamic_list): New function. + * options.h (General_options): New flags dynamic_list, + dynamic_list_data, dynamic_list_cpp_new, and + dynamic_list_cpp_typeinfo. New variable dynamic_list_. + (General_options::in_dynamic_list): New function. + * script.cc (Lex::Mode): New enum DYNAMIC_LIST. + (Lex::can_start_name): Add support for DYNAMIC_LIST mode. + (Lex::can_continue_name): Likewise. + (yylex): Likewise. + (read_script_file): New parameter script_options. + (read_dynamic_list): New function. + (Script_options::define_dynamic_list): New function. + (dynamic_list_keyword_parsecodes): New variable. + (dynamic_list_keywords): New variable. + * script.h (Script_options::define_dynamic_list): New function + prototype. + (read_dynamic_list): New function prototype. + * symtab.cc (strprefix): New macro. + (Symbol::should_add_dynsym_entry): Support dynamic_list, + dynamic_list_data, dynamic_list_cpp_new, and + dynamic_list_cpp_typeinfo. + * yyscript.y (PARSING_DYNAMIC_LIST): New token. + (dynamic_list_expr): New rule. + (dynamic_list_nodes): Likewise. + (dynamic_list_node): Likewise. + * testsuite/Makefile.am (dynamic_list): New test. + * testsuite/Makefile.in: Regenerated. + * testsuite/dynamic_list.t: New file. + * testsuite/dynamic_list.sh: New file. + +2008-11-05 Craig Silverstein + + * testsuite/tls_test_c.c: Add prototype for t11 and t11_last. + * testsuite/tls_test_c.c (t11): Add explicit "void" to prototype. + (t11_last): Likewise. + * testsuite/ver_test_6.c (main): Likewise. + +2008-10-07 Cary Coutant + + * options.c (General_options::finalize): Add check for -static and + -shared. + * gold.cc (queue_middle_tasks): Assert that list of dynamic objects + is not empty. + +2008-10-02 Cary Coutant + + * plugin.cc (make_sized_plugin_object): Fix conditional + compilation to work when not all targets are enabled. + +2008-09-29 Cary Coutant + + * archive.cc (Archive::get_file_and_offset): Use filename instead + of name to get library path. + (Archive::include_member): Unlock external member of a thin archive. + + * testsuite/Makefile.am (TEST_AR): New variable. + (thin_archive_test_1): New test. + (thin_archive_test_2): New test. + * testsuite/Makefile.in: Regenerate. + * testsuite/thin_archive_main.cc: New file. + * testsuite/thin_archive_test_1.cc: New file. + * testsuite/thin_archive_test_2.cc: New file. + * testsuite/thin_archive_test_3.cc: New file. + * testsuite/thin_archive_test_4.cc: New file. + +2008-09-29 Cary Coutant + + * mapfile.cc (Mapfile::print_input_section): Change -1U to -1ULL. + * object.cc (Sized_relobj::do_layout): Use constant invalid_address + instead of -1U. + (Sized_relobj::do_finalize_local_symbols): Likewise. + (Sized_relobj::map_to_kept_section): Likewise. + * object.h (Sized_relobj::invalid_address): New constant. + (Sized_relobj::do_output_section_offset): Check for invalid_address + and return -1ULL. + * output.cc (Output_reloc::local_section_offset): Use constant + invalid_address instead of -1U. + (Output_reloc::get_address): Likewise. + (Output_section::output_address): Change -1U to -1ULL. + * output.h (Output_reloc::invalid_address): New constant. + * reloc.cc (Sized_relobj::write_sections): Use constant + invalid_address instead of -1U. + (Sized_relobj::relocate_sections): Likewise. + * symtab.cc (Symbol_table::sized_finalize_symbol): Handle symbol + values for merge sections. + * target-reloc.h (relocate_for_relocatable): Use constant + invalid_address instead of -1U. + +2008-09-19 Cary Coutant + + Add plugin functionality for link-time optimization (LTO). + * configure.ac (plugins): Add --enable-plugins option. + * configure: Regenerate. + * config.in: Regenerate. + * Makefile.am (LIBDL): New variable. + (CCFILES): Add plugin.cc. + (HFILES): Add plugin.h. + (ldadd_var): Add LIBDL. + * Makefile.in: Regenerate. + + * archive.cc: Include "plugin.h". + (Archive::setup): Don't preread archive symbols when using a plugin. + (Archive::get_file_and_offset): Add memsize parameter. Change callers. + (Archive::get_elf_object_for_member): Call plugin hooks for claiming + files. + (Archive::include_member): Add symbols from plugin objects. + * archive.h (Archive::get_file_and_offset): Add memsize parameter. + * descriptors.cc (Descriptors::open): Check for file descriptors + abandoned by plugins. + (Descriptors::claim_for_plugin): New function. + * descriptors.h (Descriptors::claim_for_plugin): New function. + (Open_descriptor::is_claimed): New field. + (claim_descriptor_for_plugin): New function. + * fileread.cc (File_read::claim_for_plugin): New function. + * fileread.h (File_read::claim_for_plugin): New function. + (File_read::descriptor): New function. + * gold.cc: Include "plugin.h". + (queue_initial_tasks): Add task to call plugin hooks for generating + new object files. + * main.cc: Include "plugin.h". + (main): Load plugin libraries. + * object.h (Pluginobj): Declare. + (Object::pluginobj): New function. + (Object::do_pluginobj): New function. + (Object::set_target): New function. + * options.cc: Include "plugin.h". + (General_options::parse_plugin): New function. + (General_options::General_options): Initialize plugins_ field. + (General_options::add_plugin): New function. + * options.h (Plugin_manager): Declare. + (General_options): Add --plugin option. + (General_options::has_plugins): New function. + (General_options::plugins): New function. + (General_options::add_plugin): New function. + (General_options::plugins_): New field. + * plugin.cc: New file. + * plugin.h: New file. + * readsyms.cc: Include "plugin.h". + (Read_symbols::do_read_symbols): Check for archive before checking + for ELF file. Call plugin hooks to claim files. + * resolve.cc (Symbol_table::resolve): Record when symbol is referenced + from a real object file; force override when processing replacement + files. + * symtab.cc (Symbol::init_fields): Initialize in_real_elf_ field. + (Symbol::init_base_object): Likewise. + (Symbol::init_base_output_data): Likewise. + (Symbol::init_base_output_segment): Likewise. + (Symbol::init_base_constant): Likewise. + (Symbol::init_base_undefined): Likewise. + (Symbol::output_section): Assert that object is not a plugin. + (Symbol_table::add_from_pluginobj): New function. + (Symbol_table::sized_finalize_symbol): Treat symbols from plugins as + undefined. + (Symbol_table::sized_write_globals): Likewise. + (Symbol_table::add_from_pluginobj): Instantiate template. + * symtab.h (Sized_pluginobj): Declare. + (Symbol::in_real_elf): New function. + (Symbol::set_in_real_elf): New function. + (Symbol::in_real_elf_): New field. + (Symbol_table::add_from_pluginobj): New function. + + * testsuite/Makefile.am (AM_CFLAGS): New variable. + (LIBDL): New variable. + (LDADD): Add LIBDL. + (check_PROGRAMS): Add plugin_test_1 and plugin_test_2. + (check_SCRIPTS): Add plugin_test_1.sh and plugin_test_2.sh. + (check_DATA): Add plugin_test_1.err and plugin_test_2.err. + (MOSTLYCLEANFILES): Likewise. + * testsuite/Makefile.in: Regenerate. + * testsuite/plugin_test.c: New file. + * testsuite/plugin_test_1.sh: New file. + * testsuite/plugin_test_2.sh: New file. + +2008-09-16 Ian Lance Taylor + + * target-reloc.h (relocate_section): Check whether a symbol is + defined by the ABI before reporting an undefined symbol error. + * target.h (Target::is_defined_by_abi): Make parameter const. + (Target::do_is_defined_by_abi): Likewise. + * i386.cc (Target_i386::do_is_defined_by_abi): Likewise. + * powerpc.cc (Target_powerpc::do_is_defined_by_abi): Likewise. + * sparc.cc (Target_sparc::do_is_defined_by_abi): Likewise. + * x86_64.cc (Target_x86_64::do_is_defined_by_abi): Likewise. + * testsuite/Makefile.am (tls_test_shared.so): Add -Wl,-z,defs. + * testsuite/Makefile.in: Rebuild. + + * fileread.cc (make_view): Add casts to avoid warning. + +2008-09-16 Alexandre Oliva + + * i386.cc (Target_i386::define_tls_base_symbol): Update comments. + * x86_64.cc (Target_x86_64::define_tls_base_symbol): Likewise. + +2008-09-16 Alexandre Oliva + + * options.h (General_options::output_is_executable): New. + (General_options::output_is_pie): New. + * i386.cc (Target_i386::define_tls_base_symbol): Use SEGMENT_START + for shared libraries. + * x86_64.cc (Target_x86_64::define_tls_base_symbol): Likewise. + +2008-09-11 Chris Demetriou + + * options.h (origin): New -z option. + * layout.cc (Layout:finish_dynamic_section): If "-z origin" + is specified, set DF_ORIGIN in DT_FLAGS and set DF_1_ORIGIN + in DT_FLAGS_1. + +2008-09-05 Cary Coutant + + * fileread.cc (File_read::make_view): Add check for attempt to map + beyond end of file. + +2008-09-05 Cary Coutant + + * symtab.cc (Symbol_table::add_from_dynobj): Fix typos in + explicit instantiations. + +2008-08-28 Kris Van Hees + + PR gold/6858 + * options.cc (General_options::finalize): Allow undefined symbols + in shlibs if linking -shared. + + PR gold/6859 + * symtab.cc (Symbol::init_base_undefined): Mark explicitly undefined + symbols as not needing a dynsym entry. + +2008-08-20 Craig Silverstein + + * fileread.cc (File_read::open): Do not lock the file unless it + was successfully opened. + +2008-08-14 Cary Coutant + + * x86_64.cc (Target_x86_64::Relocate::relocat_tls): + Use addend for DTPOFF32, DTPOFF64, and TPOFF32 relocs. + * testsuite/tls_test.cc (struct int128): 128-bit struct + for testing TLS relocs with non-zero addend. + (v12): New TLS variable. + (t12): New test. + (t_last): Add check for v12. + * testsuite/tls_test.h (t12): New function. + * testsuite/tls_test_main.cc (thread_routine): Call new test. + +2008-08-13 Ian Lance Taylor + + * layout.cc (Layout::attach_allocated_section_to_segment): Don't + set tls_segment_ or relro_segment_. + (Layout::make_output_segment): Set tls_segment_ and relro_segment_ + when appropriate. + * output.h (Output_section::clear_is_relro): New function. + * output.cc (Output_segment::add_output_section): Handle SHF_TLS + sections specially even when output_data_ is empty. + (Output_segment::maximum_alignment): When first section is relro, + only force alignment for PT_LOAD segments. + * script.cc (script_data_segment_align): New function. + (script_data_segment_relro_end): New function. + * script-c.h (script_data_segment_align): Declare. + (script_data_segment_relro_end): Declare. + * script-sections.h (class Script_sections): Declare + data_segment_align and data_segment_relro_end. Add fields + segment_align_index_ and saw_relro_end_. + * script-sections.cc (class Sections_element): Add set_is_relro + virtual function. Add new bool* parameter to place_orphan_here. + Add get_output_section virtual function. + (class Output_section_definition): Add set_is_relro. Add new + bool* parameter to place_orphan_here. Add get_output_section. + Add is_relro_ field. + (Output_section_definition::Output_section_definition): Initialize + evaluated_address_, evaluated_load_address, evaluated_addralign_, + and is_relro_ fields. + (Output_section_definition::place_orphan_here): Add is_relro + parameter. + (Output_section_definition::set_section_addresses): Set relro for + output section. + (Output_section_definition::alternate_constraint): Likewise. + (class Orphan_output_section): Add new bool* parameter to + place_orphan_here. Add get_output_section. + (Orphan_output_section::place_orphan_here): Add is_relro + parameter. + (Script_sections::Script_sections): Initialize + data_segment_align_index_ and saw_relro_end_. + (Script_sections::data_segment_align): New function. + (Script_sections::data_segment_relro_end): New function. + (Script_sections::place_orphan): Set or clear is_relro. + (Script_sections::set_section_addresses): Force alignment of first + TLS section. + * yyscript.y (exp): Call script_data_segment_align and + script_data_segment_relro_end. + * testsuite/relro_script_test.t: New file. + * testsuite/relro_test.cc (using_script): Declare. + (t1, t2): Test using_script. + * testsuite/Makefile.am (check_PROGRAMS): Add relro_script_test. + (relro_script_test_SOURCES): Define. + (relro_script_test_DEPENDENCIES): Define. + (relro_script_test_LDFLAGS): Define. + (relro_script_test_LDADD): Define. + (relro_script_test.so): New target. + * testsuite/Makefile.in: Rebuild. + +2008-08-06 Cary Coutant + + * archive.cc (Archive::total_archives, Archive::total_members) + (Archive::total_members_loaded): New variables. + (Archive::setup): Add parameter. Add option to preread + archive symbols. + (Archive::read_armap): Add counter. + (Archive::get_file_and_offset): New function. + (Archive::get_elf_object_for_member): New function. + (Archive::read_all_symbols): New function. + (Archive::read_symbols): New function. + (Archive::add_symbols): Add counters. + (Archive::include_all_members): Use armap to find members if it's + already built. + (Archive::include_member): Skip reading symbols if already read. + Factored code into Archive::get_file_and_offset and + Archive::get_elf_object_for_member. Changed call to + Mapfile::report_include_archive_member. + (Archive::print_stats): New function. + * archive.h: Declare Object and Read_symbols_data classes. + (Archive::Archive): Add initializers for new members. + (Archive::setup): Add parameter. + (Archive::print_stats): New function. + (Archive::total_archives, Archive::total_members) + (Archive::total_members_loaded): New variables. + (Archive::get_file_and_offset): New function. + (Archive::get_elf_object_for_member): New function. + (Archive::read_all_symbols): New function. + (Archive::read_symbols): New function. + (Archive::Archive_member): New class. + (Archive::members_): New member. + (Archive::num_members_): New member. + * main.cc: Include archive.h. + (main): Call Archive::print_stats. + * mapfile.cc (Mapfile::report_include_archive_member): Delete + archive parameter; member_name is now the fully-decorated name. + * mapfile.h (Mapfile::report_include_archive_member): Likewise. + * options.h: (General_options): Add --preread-archive-symbols option. + * readsyms.cc (Read_symbols::do_read_symbols): Change call to + Archive::setup. + +2008-08-04 Ian Lance Taylor + + * symtab.h (Symbol::use_plt_offset): New function. + * i386.cc (Relocate::relocate): Call Symbol::use_plt_offset. + * powerpc.cc (Relocate::relocate): Likewise. + * sparc.cc (Relocate::relocate): Likewise. + * x86_64.cc (Relocate::relocate): Likewise. + * testsuite/weak_plt.sh: New test. + * testsuite/weak_plt_main.cc: New test. + * testsuite/weak_plt_shared.cc: New test. + * testsuite/Makefile.am (check_SCRIPTS): Add weak_plt.sh. + (check_PROGRAMS): Add weak_plt. + (check_DATA): Add weak_plt_shared.so. + (weak_plt_main_pic.o, weak_plt): New targets. + (weak_plt_shared_pic.o, weak_plt_shared.so): New targets. + * testsuite/Makefile.in: Rebuild. + + * testsuite/Makefile.am (weak_alias_test_1.so): Depend upon + gcctestdir/ld. + (weak_alias_test_2.so, weak_alias_test_4.so): Likewise. + * testsuite/Makefile.in: Rebuild. + +2008-08-04 Alan Modra + + * Makefile.am (POTFILES.in): Set LC_ALL=C. + * Makefile.in: Regenerate. + * po/POTFILES.in: Regenerate. + +2008-07-29 Ian Lance Taylor + + * script.cc (Script_options::finalize_symbols): Finalize SECTIONS + symbols before other symbols. + * testsuite/script_test_2.cc (test_addr): Declare. + (test_addr_alias): Declare. + (main): Check that test_addr and test_addr_alias have the right + values. + * testsuite/script_test_2.t: Define test_addr_alias and + test_addr. + +2008-07-24 Ian Lance Taylor + + PR 5990 + * descriptors.cc: New file. + * descriptors.h: New file. + * gold-threads.h (class Hold_optional_lock): New class. + * fileread.cc: Include "descriptors.h". + (File_read::~File_read): Release descriptor rather than closing + it. + (File_read::open) [file]: Call open_descriptor rather than open. + Set is_descriptor_opened_. + (File_read::open) [memory]: Assert that descriptor is not open. + (File_read::reopen_descriptor): New function. + (File_read::release): Release descriptor. + (File_read::do_read): Make non-const. Reopen descriptor. + (File_read::read): Make non-const. + (File_read::make_view): Reopen descriptor. + (File_read::do_readv): Likewise. + * fileread.h (class File_read): Add is_descriptor_opened_ field. + Update declarations. + * layout.cc: Include "descriptors.h". + (Layout::create_build_id): Use open_descriptor rather than open. + * output.cc: Include "descriptors.h". + (Output_file::open): Use open_descriptor rather than open. + * archive.cc (Archive::const_iterator): Change Archive to be + non-const. + (Archive::begin, Archive::end): Make non-const. + (Archive::count_members): Likewise. + * archive.h (class Archive): Update declarations. + * object.h (Object::read): Make non-const. + * Makefile.am (CCFILES): Add descriptors.cc. + (HFILES): Add descriptors.h. + * Makefile.in: Rebuild. + + PR 6716 + * gold.h: Always include . Add Solaris workarounds + following code in binutils/sysdep.h. + + PR 6048 + * ehframe.cc (Eh_frame::add_ehframe_input_section): Check whether + this->eh_frame_hdr_ is NULL before using it. + + * dynobj.cc (Versions::Versions): Update comment. + + * dynobj.cc (Versions::Versions): If there is an soname, use it as + the base version name. + + * stringpool.cc (Stringpool_template::add_with_length): Set key to + array size plus one. + (Stringpool_template::set_string_offsets): Subtract one from key + before using it as an array index. + (Stringpool_template::get_offset_with_length): Likewise. + (Stringpool_template::write_to_buffer): Likewise. + * stringpool.h (Stringpool_template::get_offset_from_key): + Likewise. + +2008-07-23 Ian Lance Taylor + + PR 6658 + * object.h (Merged_symbol_value::value): Do our best to handle a + negative addend. + + PR 6647 + * script.cc (Version_script_info::get_versions): Don't add empty + version tag to return value. + (Version_script_info::get_symbol_version_helper): Change return + type to bool. Add pversion parameter. Change all callers. + (script_register_vers_node): Don't require a non-NULL tag. + * script.h (class Version_script_info): Update declarations. + (Version_script_info::get_symbol_version): Change return type to + bool. Add version parameter. Change all callers. + * symtab.cc (Sized_symbol::add_from_relobj): Rework version + handling. Handle an empty version from a version script. + (Symbol_table::define_special_symbol): Likewise. + * testsuite/ver_test_10.script: New file. + * testsuite/ver_test_10.sh: New file. + * testsuite/Makefile.am (check_SCRIPTS): Add ver_test_10.sh. + (check_DATA): Add ver_test_10.syms. + (ver_test_10.syms, ver_test_10.so): New target. + * testsuite/Makefile.in: Rebuild. + +2008-07-23 Simon Baldwin + + * symtab.cc (Symbol_table::sized_write_symbol): Only set st_size + to zero for undefined symbols from dynamic libraries. + +2008-07-23 Ian Lance Taylor + + * symtab.cc (Symbol_table::resolve): Remove version parameter. + Change all callers. + * symtab.h (class Symbol_table): Update declaration. + * testsuite/ver_test_9.cc: New file. + * testsuite/Makefile.am (check_PROGRAMS): Add ver_test_9. + (ver_test_9_SOURCES, ver_test_9_DEPENDENCIES): Define. + (ver_test_9_LDFLAGS, ver_test_9_LDADD): Define. + (ver_test_9.so, ver_test_9.o): New targets. + * testsuite/Makefile.in: Rebuild. + +2008-07-22 Ian Lance Taylor + + * options.h (class General_options): Define --check-sections. + * layout.cc (Layout::set_segment_offsets): Handle + --check-sections. + + * options.h (class General_options): Define -n/--nmagic and + -N/--omagic. + * options.cc (General_options::finalize): For -n/--nmagic or + -N/--omagic, set -static. + * layout.cc (Layout::attach_allocated_section_to_segment): If + -N/--omagic, don't put read-only and read-write sections in + different segments. + (Layout::find_first_load_seg): If -N/--omagic, don't insist on + finding a read-only segment. + (Layout::set_segment_offsets): If -N/--omagic or -n/--nmagic, + don't set the minimum segment alignment to the common page size, + and don't set the file offset to the address modulo the page size. + * script-sections.cc (Script_sections::create_segments): If + -n/--omagic, don't put read-only and read-write sections in + different segments. + + * cref.cc: New file. + * cref.h: New file. + * options.h (class General_options): Add --print-symbol-counts. + * main.cc (main): Issue defined symbol report if requested. + * archive.cc (Archive::interpret_header): Make into a const member + function. + (Archive::add_symbols): Call Input_objects::archive_start and + archive_stop. + (Archive::const_iterator): Define new class. + (Archive::begin, Archive::end): New functions. + (Archive::include_all_members): Rewrite to use iterator. + (Archive::count_members): New function. + * archive.h (class Archive): Update declarations. + (Archive::filename): New function. + * object.cc: Include "cref.h". + (Sized_relobj::Sized_relobj): Initialize defined_count_. + (Sized_relobj::do_get_global_symbol_counts): New function. + (Input_objects::add_object): Add object to cross-referencer. + (Input_objects::archive_start): New function. + (Input_objects::archive_stop): New function. + (Input_objects::print_symbol_counts): New function. + * object.h: Declare Cref and Archive. + (Object::get_global_symbol_counts): New function. + (Object::do_get_global_symbol_counts): New pure virtual function. + (class Sized_relobj): Add defined_count_ field. Update + declarations. + (class Input_objects): Add cref_ field. Update constructor. + Update declarations. + * dynobj.cc (Sized_dynobj::Sized_dynobj): Initialize symbols_ and + defined_count_. + (Sized_dynobj::do_add_symbols): Allocate symbols_ if printing + symbol counts. + (Sized_dynobj::do_get_global_symbol_counts): New function. + * dynobj.h (class Sized_dynobj): Add fields symbols_ and + defined_count_. Update declarations. Define Symbols typedef. + * symtab.cc (Symbol_table::add_from_relobj): Add defined + parameter. Change all callers. + (Symbol_table::add_from_dynobj): Add sympointers and defined + parameters. Change all callers. + * symtab.h (class Symbol_table): Update declarations. + * Makefile.am (CCFILES): Add cref.cc. + (HFILES): Add cref.h. + * Makefile.in: Rebuild. + +2008-07-22 Simon Baldwin + + * symtab.cc (Symbol_table::sized_write_symbol): Set symbol size + to zero when writing undefined symbols. + +2008-07-22 Ian Lance Taylor + + * output.cc (Output_section::add_input_section): Don't try to + merge empty merge sections. + +2008-07-21 Craig Silverstein + + * symtab.cc (Symbol_table::warn_about_undefined_dynobj_symbol): + Include symbol version in error message. + +2008-07-20 Chris Demetriou + + * configure.ac (gold_cv_c_random_seed): New configured variable. + (RANDOM_SEED_CFLAGS): New substituted variable. + * Makefile.am (AM_CFLAGS, AM_CXXFLAGS): Add $(RANDOM_SEED_CFLAGS). + * configure: Rebuild. + * Makefile.in: Likewise. + * testsuite/Makefile.in: Likewise. + +2008-07-18 Ian Lance Taylor + + * symtab.cc (Symbol_table::add_from_object): Rewrite the case + where we see NAME/NULL and NAME/VERSION as separate symbols. + * testsuite/ver_test_main.cc (main): Call t4. + (t4, t4_2a): Define. + * testsuite/ver_test_2.cc (t4_2): Define. + * testsuite/ver_test_2.script: Put t4_2a in VER2. + * testsuite/ver_test_4.cc (t4_2a): Define. + * testsuite/ver_test_4.script: Put t4_2a in VER2. + * testsuite/ver_test.h (t4, t4_2, t4_2a): Declare. + +2008-07-17 Ian Lance Taylor + + * dynobj.cc (Versions::add_def): If we give an error about a + missing version, go ahead and create the version anyhow. + +2008-07-10 Ian Lance Taylor + + Handle output sections with more than 0x7fffffff bytes. + * object.h (class Relobj): Change map_to_output_ to + output_sections_, and just keep a section pointer. Change all + uses. Move comdat group support to Sized_relobj. + (Relobj::is_section_specially_mapped): Remove. + (Relobj::output_section): Remove poff parameter. Change all + callers. + (Relobj::output_section_offset): New function. + (Relobj::set_section_offset): Rewrite. + (Relobj::map_to_output): Remove. + (Relobj::output_sections): New function. + (Relobj::do_output_section_offset): New pure virtual function. + (Relobj::do_set_section_offset): Likewise. + (class Sized_relobj): Add section_offsets_ field. Add comdat + group support from Relobj. Update declarations. + (Sized_relobj::get_output_section_offset): New function. + (Sized_relobj::do_output_section_offset): New function. + (Sized_relobj::do_set_section_offset): New function. + * object.cc (Relobj::output_section_address): Remove. + (Sized_relobj::Sized_relobj): Initialize new fields. + (Sized_relobj::include_section_group): Cast find_kept_object to + Sized_relobj. + (Sized_relobj::include_linkonce_section): Likewise. + (Sized_relobj::do_layout): Use separate arrays for output section + and output offset. + (Sized_relobj::do_count_local_symbols): Change map_to_output to + output_sections. + (Sized_relobj::do_finalize_local_symbols): Change map_to_output to + output_sections and section_offsets. + (Sized_relobj::write_local_symbols): Likewise. + (map_to_kept_section): Compute output address directly. + * reloc.cc (Sized_relobj::do_read_relocs): Change map_to_output to + output_sections and section_offsets. + (Sized_relobj::write_sections): Likewise. + (Sized_relobj::relocate_sections): Likewise. + * symtab.cc (sized_finalize_symbol): Use output_section_offset. + * output.h (class Output_reloc): Update declarations. Change + u2_.relobj to Sized_relobj*. + (class Output_data_reloc): Change add functions to use + Sized_relobj*. + * output.cc (Output_reloc::Output_reloc): Change relobj to + Sized_relobj*. + (Output_reloc::local_section_offset): Change return type to + Elf_Addr. Use get_output_section_offset. + (Output_reloc::get_address): Likewise. + (Output_section::is_input_address_mapped): Don't call + is_section_specially_mapped. + (Output_section::output_offset): Likewise. + (Output_section::output_address): Likewise. + (Output_section::starting_output_address): Likewise. + * copy-relocs.cc (Copy_relocs::copy_reloc): Change object + parameter to Sized_relobj*. + (Copy_relocs::need_copy_reloc): Likewise. + (Copy_relocs::save): Likewise. + * copy-relocs.h (class Copy_relocs): Update declarations. + (class Copy_relocs::Copy_reloc_entry): Change constructor to use + Sized_relobj*. Change relobj_ field to Sized_relobj*. + * target-reloc.h (relocate_for_relocatable): Change + offset_in_output_section type to Elf_Addr. Change code that uses + it as well. + * layout.cc (Layout::layout): Always set *off. + * mapfile.cc (Mapfile::print_input_section): Use + output_section_offset. + * i386.cc (Target_i386::copy_reloc): Change object parameter to + Sized_relobj*. + * powerpc.cc (Target_powerpc::copy_reloc): Likewise. + * sparc.cc (Target_sparc::copy_reloc): Likewise. + * x86_64.cc (Target_x86_64::copy_reloc): Likewise. + +2008-07-03 Ian Lance Taylor + + * layout.cc (Layout::include_section): Do not discard unrecognized + SHT_STRTAB sections. + +2008-06-30 Craig Silverstein + + * script.cc (Lex::can_continue_name): Make '?' allowable in + version-script names. + * testsuite/version_script.map: Change glob pattern to use '?' + +2008-06-30 Manish Singh + + PR 6585 + * symtab.cc (Symbol_table::add_undefined_symbols_from_command_line): + Correct typo. + +2008-06-30 Ian Lance Taylor + + PR 6660 + PR 6682 + * powerpc.cc (Powerpc_relocate_functions::addr16_ha) [both + versions]: Don't try to read the value in the contents, since we + don't use it. Use the template endianness when writing. + +2008-06-25 Cary Coutant + + * fileread.cc (File_read::make_view): Assert on zero-length view. + * object.cc (Sized_relobj::do_read_symbols): Don't try to read + symbol table when there are no symbols to read. + +2008-06-23 Craig Silverstein + + * version.cc (version_string): Bump to 1.7 + +2008-06-18 Craig Silverstein + + * powerpc.cc (Powerpc_relocate_functions::addr16_ha): cast + constant 0xFFFF to type Valtype. + (Powerpc_relocate_functions::rel16_ha): Likewise. + +2008-06-17 Ian Lance Taylor + + * output.h (Output_section::Input_section): Initialize p2align_ to + zero for Output_section_data constructors. + (Output_section::Input_section::addralign): If not an input + section, return the alignment of the Output_section_data. + * testsuite/copy_test.cc: New file. + * testsuite/copy_test_1.cc: New file. + * testsuite/copy_test_2.cc: New file. + * testsuite/Makefile.am (check_PROGRAMS): Add copy_test. + (copy_test_SOURCES, copy_test_DEPENDENCIES): New variables. + (copy_test_LDFLAGS, copy_test_LDADD): New variables. + (copy_test_1_pic.o, copy_test_1.so): New targets. + (copy_test_2_pic.o, copy_test_2.so): New targets. + * testsuite/Makefile.in: Rebuild. + + * script-sections.cc (Script_sections::place_orphan): Initialize + local variable exact. + +2008-06-13 David Edelsohn + + * powerpc.cc (Output_data_plt_powerpc::do_write): 8 + 4 = 0xC. + +2008-06-12 David Edelsohn + David S. Miller + + * powerpc.cc: New file. + * Makefile.am (TARGETSOURCES): Add powerpc.cc + (ALL_TARGETOBJS): Add powerpc.$(OBJEXT) + * configure.tgt: Add entries for powerpc-* and powerpc64-*. + * Makefile.in: Rebuild. + +2008-06-09 Ian Lance Taylor + + * testsuite/relro_test.cc: Include , , and + . + (throwing, orig_terminate): New static variables. + (terminate_handler): New static function. + (t2): Set terminate handler. + +2008-06-05 Kris Van Hees + + PR 6584 + * binary.cc (Binary_to_elf::sized_convert): Fix .data + alignment. + +2008-05-30 Cary Coutant + + * archive.cc (Archive::include_all_members) Correct to step + over symbol table and extended name table in thin archives. + +2008-05-29 Kris Van Hees + + PR 6407 + * target-reloc.h (relocate_for_relocatable): Fix new_offset + calculation. + +2008-05-28 Caleb Howe + + * reduced_debug_output.cc: New file. + * reduced_debug_output.h: New file. + * options.h (class General_options): Add --strip-debug-non-line. + * options.cc (General_options::finalize): Add strip_debug_non_line + to the strip heirarchy. + * layout.h (class Layout): Add debug_abbrev_ and debug_info_ + fields. + * layout.cc: Include "reduced_debug_output.h". + (Layout::Layout): Initialize new fields. + (line_only_debug_sections): New static array. + (is_lines_only_debug_sections): New static inline function. + (Layout::include_section): Handle --strip-debug-non-line. + (Layout::make_output_section): If --strip-debug-non-line, build + new output sections for .debug_abbrev and .debug_info. + * dwarf_reader.cc (read_unsigned_LEB_128): Move to namespace + gold. Warn about possible overflow. + (read_signed_LEB_128): Likewise. + * dwarf_reader.h: (read_unsigned_LEB_128): Declare. + (read_signed_LEB_128): Declare. + * Makefile.am (CCFILES): Add reduced_debug_output.cc. + (HFILES): Add reduced_debug_output.h. + * Makefile.in: Rebuild. + +2008-05-21 Ian Lance Taylor + + * mapfile.cc: New file. + * mapfile.h: New file. + * options.h (class General_options): Add -M/--print-map and -Map. + * options.cc (General_options::finalize): Make -M equivalent to + -Map -. + * main.cc: Include and "mapfile.h". + (main): Open mapfile if requested. + * gold.cc (class Middle_runner): Add mapfile_ field. Update + constructor. Change caller. + (queue_initial_tasks): Add mapfile parameter. Change caller. + (queue_middle_tasks): Likewise. + * gold.h (queue_initial_tasks, queue_middle_tasks): Update + declarations. + * archive.cc: Include "mapfile.h". + (Archive::add_symbols): Add mapfile parameter. Change all + callers. Pass mapfile, symbol, and reason to include_member. + (Archive::include_all_members): Add mapfile parameter. Change all + callers. + (Archive::include_member): Add mapfile, sym, and why parameters. + Change all callers. Report inclusion to map file. + * archive.h: Include "fileread.h". + (class Archive): Update declarations. + (Archive::file): New const method. + (class Add_archive_symbols): Add mapfile_ field. Update + constructor. Change all callers. + * readsyms.h (class Read_symbols): Likewise. + (class Finish_group): Likewise. + (class Read_script): Likewise. + * common.cc: Include "mapfile.h". + (Symbol_table::allocate_commons): Add mapfile parameter. Change + all callers. + (Symbol_table::do_allocate_commons): Likewise. + (Symbol_table::do_allocate_commons_list): Likewise. Report common + symbol allocation to mapfile. + * common.h (class Allocate_commons_task): Add mapfile_ field. + Update constructor. Change all callers. + * symtab.h (class Symbol_table): Update declarations. + * layout.cc: Include "mapfile.h". + (Layout_task_runner::run): Print information to mapfile. + (Layout::create_gold_note): Change Output_data_fixed_space to + Output_data_zero_fill. + (Layout::create_build_id): Likewise. + (Layout::print_to_mapfile): New function. + * layout.h (class Layout_task_runner): Add mapfile_ field. Update + constructor. Change caller. + (class Layout): Declare print_to_mapfile. + * output.cc (Output_section::Input_section::print_to_mapfile): New + function. + (Output_section::add_input_section): If producing a map, always + add to input_sections_ list. + (Output_section::do_print_to_mapfile): New function. + (Output_segment::print_sections_to_mapfile): New function. + (Output_segment::print_section_list_to_mapfile): New function. + * output.h: Include "mapfile.h". + (Output_data::print_to_mapfile): New function. + (Output_data::do_print_to_mapfile): New virtual function. + (Output_segment_headers::do_print_to_mapfile): New function. + (Output_file_header::do_print_to_mapfile): New function. + (Output_data_const::do_print_to_mapfile): New function. + (class Output_data_const_buffer): Add map_name_ field. Update + constructor. Change all callers. Add do_print_to_mapfile + function. + (class Output_data_fixed_space): Likewise. + (class Output_data_space): Likewise. + (class Output_data_zero_fill): New class. + (Output_data_strtab::do_print_to_mapfile): New function. + (Output_data_reloc_base::do_print_to_mapfile): New function. + (Output_relocatable_relocs::do_print_to_mapfile): New function. + (Output_data_group::do_print_to_mapfile): New function. + (Output_data_got::do_print_to_mapfile): New function. + (Output_data_dynamic::do_print_to_mapfile): New function. + (Output_symtab_xindex::do_print_to_mapfile): New function. + (class Output_section): Declare do_print_to_mapflie. Declare + print_to_mapfile in Input_section. + (class Output_segment): Declare new functions. + * object.h (Sized_relobj::symbol_count): New function. + * script-sections.cc + (Output_section_element_dot_assignment::set_section_addresses): + Change Output_data_fixed_space to Output_data_zero_fill. + (Output_data_expression::do_print_to_mapfile): New function. + * script.cc (read_input_script): Add mapfile parameter. Change + all callers. + * script.h (read_input_script): Update declaration. + * ehframe.h (Eh_frame_hdr::do_print_to_mapfile): New function. + (Eh_frame::do_print_to_mapfile): New function. + * merge.h (Output_merge_data::do_print_to_mapfile): New function. + (Output_merge_string::do_print_to_mapfile): New function. + * i386.cc (Output_data_plt_i386::do_print_to_mapfile): New + function. + * sparc.cc (Output_data_plt_sparc::do_print_to_mapfile): New + function. + * x86_64.cc (Output_data_plt_x86_64::do_print_to_mapfile): New + function. + * Makefile.am (CCFILES): Add mapfile.cc. + (HFILES): Add mapfile.h. + * Makefile.in: Rebuild. + +2008-05-19 Ian Lance Taylor + + * options.h (class General_options): Add -z relro. + * layout.cc (Layout::Layout): Initialize relro_segment_. + (Layout::add_output_section_data): Return the output section. + (Layout::make_output_section): Rcognize relro sections and mark + them appropriately. + (Layout::attach_allocated_section_to_segment): Put relro sections + in a PT_GNU_RELRO segment. + (Layout::create_initial_dynamic_sections): Mark the .dynamic + section as relro. + (Layout::segment_precedes): Sort PT_GNU_RELRO segments after + PT_TLS segments. + (Layout::linkonce_mapping): Map d.rel.ro.local to + .data.rel.ro.local. + (Layout::output_section_name): Us .data.rel.ro.local for any + section which begins with that. + * layout.h (class Layout): Update add_output_section_data + declaration. Add relro_segment_ field. + * output.cc (Output_section::Output_section): Initialize is_relro_ + and is_relro_local_ fields. + (Output_segment::add_output_section): Group relro sections. + (Output_segment::is_first_section_relro): New function. + (Output_segment::maximum_alignment): If there is a relro section, + align the segment to the common page size. + (Output_segment::set_section_addresses): Track whether we are + looking at relro sections. If the last section is a relro + section, align to the common page size. + (Output_segment::set_section_list_addresses): Add in_relro + parameter. Change all callers. Align to the page size when + moving from relro to non-relro section. + (Output_segment::set_offset): Align memsz of a PT_GNU_RELRO + segment. + * output.h (class Output_section): Add is_relro_ and + is_relro_local_ fields. + (Output_section::is_relro): New function. + (Output_section::set_is_relro): New function. + (Output_section::is_relro_local): New function. + (Output_section::set_is_relro_local): New function. + (class Output_segment): Update declarations. + * i386.cc (Target_i386::got_section): Mark .got section as relro. + * sparc.cc (Target_sparc::got_section): Likewise. + * x86_64.cc (Target_x86_64::got_section): Likewise. + * testsuite/relro_test_main.cc: New file. + * testsuite/relro_test.cc: New file. + * testsuite/Makefile.am (check_PROGRAMS): Add relro_test. + (relro_test_SOURCES, relro_test_DEPENDENCIES): New variables. + (relro_test_LDFLAGS, relro_test_LDADD): New variables. + (relro_test.so, relro_test_pic.o): New targets. + * testsuite/Makefile.in: Rebuild. + +2008-05-16 Ian Lance Taylor + + * output.cc (Output_segment::add_output_section): Remove front + parameter. + * output.h (class Output_segment): Remove + add_initial_output_section and overloaded add_output_section. + Update declaration of remaining add_output_section. + * layout.cc (Layout::create_interp): Call add_output_section + rather than add_initial_output_section. + (Layout::finish_dynamic_section): Likewise. + + * i386.cc (Target_i386::Relocate::relocate_tls): Set dynamic type + for TLS_GOTDESC and TLS_DESC_CALL. Only optimize TLS_LDO_32 if we + know the dynamic type. + * x86_64.cc (Target_x86_64::Relocate): Add saw_tls_block_reloc_ + field. Initialize it in constructor. + (Target_x86_64::Relocate::relocate_tls): Record that we saw a TLS + block reloc for TLSGD, GOTPC32_TLSDESC, TLSDESC_CALL, and TLSLD. + Only optimize DTPOFF32 and DTPOFF64 if we have seen a TLS block + reloc. + + * output.cc (Output_reloc::get_address): Change return type to + Elf_Addr. + * output.h (class Output_reloc): Update get_address declaration. + * x86_64.cc (Output_data_plt_x86_64::do_write): Use 64-bit types + for section addresses. + +2008-05-09 Ian Lance Taylor + + PR 6493 + * gold.cc (gold_nomem): Use return value of write. + +2008-05-08 Ian Lance Taylor + + * symtab.c (Symbol::init_base_output_data): Add version + parameter. Change all callers. + (Symbol::init_base_output_segment): Likewise. + (Symbol::init_base_constant): Likewise. + (Symbol::init_base_undefined): Likewise. + (Sized_symbol::init_output_data): Likewise. + (Sized_symbol::init_output_segment): Likewise. + (Sized_symbol::init_constant): Likewise. + (Sized_symbol::init_undefined): Likewise. + (Symbol_table::do_define_in_output_data): If the new symbol has a + version, mark it as the default. + (Symbol_table::do_define_in_output_segment): Likewise. + (Symbol_table::do_define_as_constant): Likewise. + * symtab.h (class Symbol): Update declarations. + (class Sized_symbol): Likewise. + * resolve.cc (Symbol::override_version): New function. + (Symbol::override_base): Call override_version. + (Symbol::override_base_with_special): Likewise. + * testsuite/ver_script_8.script: New file. + * testsuite/Makefile.am (check_PROGRAMS): Add ver_test_8. + (ver_test_8_SOURCES, ver_test_8_DEPENDENCIES): Define. + (ver_test_8_LDFLAGS, ver_test_8_LDADD): Define. + (ver_test_8_1.so, ver_test_8_2.so): New targets. + +2008-05-06 Ian Lance Taylor + + PR 6049 + * options.h (DEFINE_set): Add VARNAME_begin and VARNAME_end + functions. + (class General_options): Remove existing --undefined, and add + --no-undefined instead. Add new --undefined as synonym for -u. + * archive.cc (Archive::add_symbols): Check whether symbol was + named with -u. + * gold.cc (queue_middle_tasks): Add -u symbols to symbol table. + * symtab.h (class Symbol): Rename CONSTANT to IS_CONSTANT; change + all uses. Add IS_UNDEFINED. Update declarations to split + different versions of init_base. Declare init_base_undefined. + (Symbol::is_defined): Handle IS_UNDEFINED. + (Symbol::is_undefined): Likewise. + (Symbol::is_weak_undefined): Call is_undefined. + (Symbol::is_absolute): Handle IS_CONSTANT. + (class Sized_symbol): Update declarations to split different + versions of init. Declare init_undefined. + (class Symbol_table): Declare new functions. + * symtab.cc (Symbol::init_base_object): Rename from init_base. + Change all callers. + (Symbol::init_base_output_data): Likewise. + (Symbol::init_base_output_segment): Likewise. + (Symbol::init_base_constant): Likewise. + (Symbol::init_base_undefined): New function. + (Sized_symbol::init_object): Rename from init. Change all + callers. + (Sized_symbol::init_output_data): Likewise. + (Sized_symbol::init_output_segment): Likewise. + (Sized_symbol::init_constant): Likewise. + (Sized_symbol::init_undefined): New function. + (Symbol_table::add_undefined_symbols_from_command_line): New + function. + (Symbol_table::do_add_undefined_symbols_from_command_line): New + function. + (Symbol::final_value_is_known): Handle IS_UNDEFINED. + (Symbol::output_section): Likewise. + (Symbol::set_output_section): Likewise. + (Symbol_table::sized_finalize_symbol): Likewise. + (Symbol_table::sized_write_globals): Likewise. + * resolve.cc (Symbol_table::should_override): Likewise. + (Symbol::override_base_with_special): Likewise. + + * symtab.cc (Symbol_table::add_from_dynobj): If we see a protected + symbol, change it to have default visibility. + * testsuite/protected_1.cc: New file. + * testsuite/protected_2.cc: New file. + * testsuite/protected_3.cc: New file. + * testsuite/protected_main_1.cc: New file. + * testsuite/protected_main_2.cc: New file. + * testsuite/protected_main_3.cc: New file. + * testsuite/Makefile.am (check_PROGRAMS): Add protected_1. + (protected_1_SOURCES, protected_1_DEPENDENCIES): Define. + (protected_1_LDFLAGS, protected_1_LDADD): Define. + (protected_1.so): New target. + (protected_1_pic.o, protected_2_pic.o): New targets. + (protected_3_pic.o): New target. + (check_PROGRAMS): Add protected_2. + (protected_2_SOURCES, protected_2_DEPENDENCIES): Define. + (protected_2_LDFLAGS, protected_2_LDADD): Define. + * testsuite/Makefile.in: Rebuild. + + * options.h (DEFINE_var): Add set_user_set_##varname__. + (DEFINE_bool_alias): New macro. + (class General_options): Define -Bstatic using DEFINE_bool_alias + rather than DEFINE_special. Add --undefined as an alias for -z + defs. + * options.cc (General_options::parse_Bstatic): Remove. + + * options.h (class General_options): Add --fatal-warnings. + * main.cc (main): Implement --fatal-warnings. + * errors.h (Errors::warning_count): New function. + + * options.h (class General_options): Add -Bsymbolic-functions. + * symtab.h (Symbol::is_preemptible): Check for + -Bsymbolic-functions. + +2008-05-05 Ian Lance Taylor + + * options.h (DEFINE_bool): For DASH_Z, create the negative option + as noVARNAME rather than no-VARNAME. + (class General_options): Add option -z combreloc. + * output.h (class Output_reloc) [SHT_REL]: Declare compare and + get_address. + (Output_reloc::sort_before) [SHT_REL]: New function. + (Output_reloc::sort_before) [SHT_RELA]: New function. + (class Output_data_reloc_base): Add sort_relocs_ field. Define + Sort_relocs_comparison. + (Output_data_reloc_base::Output_data_reloc_base): Add sort_relocs + parameter. Change all callers. + (Output_data_reloc::Output_data_reloc) [both versions]: Add + sort_relocs parameter. Change all callers. + * output.cc (Output_reloc::get_address): New function, broken out + of write_rel. + (Output_reloc::write_rel): Call it. + (Output_reloc::compare): New function. + (Output_data_reloc_base::do_write): Optionally sort relocs. + + * configure.ac: If targ_extra_obj is set, link it in. + * configure.tgt: Initialize all variables. + (x86_64*): Set targ_extra_obj and targ_extra_size. + * configure: Rebuild. + + * object.cc (Sized_relobj::include_section_group): Adjust section + indexes read from group data. Build vector to pass to + layout_group. + * layout.cc (Layout::layout_group): Add flags and shndxes + parameters. Remove contents parameter. Change caller. Update + explicit instantiations. + * layout.h (class Layout): Update layout_group declaration. + * output.cc (Output_data_group::Output_data_group): Add flags and + input_shndxes parameters. Remove contents parameter. Change + caller. + (Output_data_group::do_write): Change input_sections_ to + input_shndxes_. + * output.h (class Output_data_group): Update constructor + declaration. Rename input_sections_ to input_shndxes_. + * testsuite/many_sections_test.cc: Add template. + +2008-04-30 Cary Coutant + + * target-reloc.h (relocate_section): Fix dead-pointer bug. + + * layout.cc (Layout::include_section): Refactored check for debug + info section. + (Layout::add_comdat): Add new parameters. Change type + of signature parameter. Add object and shndx to signatures table. + (Layout::find_kept_object): New function. + * layout.h: Include . + (Layout::is_debug_info_section): New function. + (Layout::add_comdat): Add new parameters. + (Layout::find_kept_object): New function. + (Layout::Kept_section): New struct. + (Layout::Signatures): Change type of map range. + * object.cc (Relobj::output_section_address): New function. + (Sized_relobj::include_section_group): Add new parameters. Change + calls to Layout::add_comdat. Change to build table of kept comdat + groups and table mapping discarded sections to kept sections. + (Sized_relobj::include_linkonce_section): Likewise. Add new parameter. + (Sized_relobj::do_layout): Change calls to include_section_group and + include_linkonce_section. + (Sized_relobj::do_finalize_local_symbols): Do not set local symbol + value to zero when section is discarded. + (Sized_relobj::map_to_kept_section): New function. + * object.h (Relobj::output_section_address): New function. + (Relobj::Comdat_group): New type. + (Relobj::find_comdat_group): New function. + (Relobj::Comdat_group_table): New type. + (Relobj::Kept_comdat_section): New type. + (Relobj::Kept_comdat_section_table): New type. + (Relobj::add_comdat_group): New function. + (Relobj::set_kept_comdat_section): New function. + (Relobj::get_kept_comdat_section): New function. + (Relobj::comdat_groups_): New field. + (Relobj::kept_comdat_sections_): New field. + (Symbol_value::input_value): Update comment. + (Sized_relobj::map_to_kept_section) New function. + (Sized_relobj::include_linkonce_section): Add new parameter. + * target-reloc.h (Comdat_behavior): New type. + (get_comdat_behavior): New function. + (relocate_section): Add code to map a discarded section to the + corresponding kept section when applying a relocation. + +2008-04-30 Craig Silverstein + + * dwarf_reader.cc (next_generation_count): New static var. + (Addr2line_cache_entry): New struct. + (addr2line_cache): New static var. + (Dwarf_line_info::one_addr2line): Added caching. + (Dwarf_line_info::clear_addr2line_cache): New function. + * dwarf_reader.h (Dwarf_line_info::one_addr2line): Add + cache-size parameter. + (Dwarf_line_info::one_addr2line_cache): New function. + * symtab.cc (Symbol_table::detect_odr_violations): Pass + new cache-size argument to one_addr2line(), and clear cache. + +2008-04-28 Cary Coutant + + * i386.cc (Relocate::relocate): Fix typos for R_386_PC16 and + R_386_PC8 relocations. + +2008-04-23 Ian Lance Taylor + + * object.cc (Sized_relobj::include_section_group): Check for + invalid section group. + + * object.cc (make_elf_object): Correct test for 64-bit ELF file + header size. + + * readsyms.cc (Read_symbols::do_read_symbols): Use get_view rather + than read for file header. + * archive.cc (Archive::include_member): Likewise. + +2008-04-23 Paolo Bonzini + + * aclocal.m4: Regenerate. + * configure: Regenerate. + +2008-04-19 Ian Lance Taylor + + * version.cc (version_string): Bump to 1.6. + + * testsuite/Makefile.am (many_sections_r_test): New target. + (many_sections_r_test_SOURCES): Remove. + (many_sections_r_test_DEPENDENCIES): Remove. + (many_sections_r_test_LDFLAGS): Remove. + (many_sections_r_test_LDADD): Remove. + + * object.cc (Sized_relobj::do_add_symbols): Always pass + local_symbol_count_ to add_from_relobj. + + * testsuite/Makefile.am (many_sections_check.h): Only check one in + every thousand variables. + * testsuite/Makefile.in: Rebuild. + + * object.cc (Xindex::initialize_symtab_xindex): New function. + (Xindex::read_symtab_xindex): New function. + (Xindex::sym_xindex_to_shndx): New function. + (Sized_relobj::find_symtab): Pick up SHT_SYMTAB_SHNDX section if + available. + (Sized_relobj::do_initialize_xindex): New function. + (Sized_relobj::do_read_symbols): Adjust section links. + (Sized_relobj::symbol_section_and_value): Add is_ordinary + parameter. Change all callers. + (Sized_relobj::include_section_group): Adjust section links and + symbol section indexes. + (Sized_relobj::do_layout): Adjust section links. + (Sized_relobj::do_count_local_symbols): Adjust section links and + symbol section indexes. + (Sized_relobj::do_finalize_local_symbols): Distinguish between + ordinary and special symbols. + (Sized_relobj::write_local_symbols): Add symtab_xindex and + dynsym_xindex parameters. Change all callers. Adjust section + links. Use SHN_XINDEX when needed. + (Sized_relobj::get_symbol_location_info): Adjust section links. + Don't get fooled by special symbols. + * object.h (class Xindex): Define. + (class Object): Add xindex_ parameter. Declare virtual functoin + do_initialize_xindex. + (Object::adjust_sym_shndx): New function. + (Object::set_xindex): New protected function. + (class Symbol_value): Add is_ordinary_shndx_ field. + (Symbol_value::Symbol_value): Initialize is_ordinary_shndx_. + (Symbol_value::value): Assert ordinary section. + (Symbol_value::initialize_input_to_output_map): Likewise. + (Symbol_value::set_input_shndx): Add is_ordinary parameter. + Change all callers. + (Symbol_value::input_shndx): Add is_ordinary parameter. Change + all callers. + (class Sized_relobj): Update declarations. + (Sized_relobj::local_symbol_input_shndx): Add is_ordinary + parameter. Change all callers. + (Sized_relobj::adjust_shndx): New function. + * dynobj.cc (Sized_dynobj::Sized_dynobj): Initialize dynsym_shndx_ + field. + (Sized_dynobj::find_dynsym_sections): Remove pdynsym_shndx + parameter. Change all callers. Pick up SHT_DYNSYM_SHNDX section + for SHT_DYNSYM section if available. Set dynsym_shndx_ field. + (Sized_dynobj::read_dynsym_section): Adjust section links. + (Sized_dynobj::read_dynamic): Likewise. + (Sized_dynobj::do_read_symbols): Use dynsym_shndx_ field. Adjust + section links. + (Sized_dynobj::do_initialize_xindex): New function. + * dynobj.h (class Sized_dynobj): Add dynsym_shndx_ field. Declare + do_initialize_xindex. + (Sized_dynobj::adjust_shndx): New function. + * layout.cc (Layout::Layout): Initialize symtab_xindex_ and + dynsym_xindex_ fields. + (Layout::finalize): Add a call to set_section_indexes before + creating the symtab sections. + (Layout::set_section_indexes): Don't do anything if the section + already has a section index. + (Layout::create_symtab_sections): Add shnum parameter. Change + caller. Create .symtab_shndx section if needed. + (Layout::create_shdrs): Add shstrtab_section parameter. Change + caller. + (Layout::allocated_output_section_count): New function. + (Layout::create_dynamic_symtab): Create .dynsym_shndx section if + needed. + * layout.h (class Layout): Add symtab_xindex_ and dynsym_xindex_ + fields. Update declarations. + (Layout::symtab_xindex): New function. + (Layout::dynsym_xindex): New function. + (class Write_symbols_task): Add layout_ field. + (Write_symbols_task::Write_symbols_task): Add layout parameter. + Change caller. + * output.cc (Output_section_headers::Output_section_headers): Add + shstrtab_section parameter. Change all callers. + (Output_section_headers::do_sized_write): Store overflow values + for section count and section string table section index in + section header zero. + (Output_file_header::do_sized_write): Check for overflow of + section count and section string table section index. + (Output_symtab_xindex::do_write): New function. + (Output_symtab_xindex::endian_do_write): New function. + * output.h (class Output_section_headers): Add shstrtab_section_. + Update declarations. + (class Output_symtab_xindex): Define. + (Output_section::has_out_shndx): New function. + * symtab.cc (Symbol::init_fields): Initialize is_ordinary_shndx_ + field. + (Symbol::init_base): Add st_shndx and is_ordinary parameters. + Change all callers. + (Sized_symbol::init): Likewise. + (Symbol::output_section): Check for ordinary symbol. + (Symbol_table::add_from_object): Remove orig_sym parameter. Add + st_shndx, is_ordinary, and orig_st_shndx parameters. Change all + callers. + (Symbol_table::add_from_relobj): Add symndx_offset parameter. + Change all callers. Simplify handling of symbols from sections + not included in the link. + (Symbol_table::add_from_dynobj): Handle ordinary symbol + distinction. + (Weak_alias_sorter::operator()): Assert that symbols are + ordinary. + (Symbol_table::sized_finalize_symbol): Handle ordinary symbol + distinction. + (Symbol_table::write_globals): Add symtab_xindex and dynsym_xindex + parameters. Change all callers. + (Symbol_table::sized_write_globals): Likewise. Handle ordinary + symbol distinction. Use SHN_XINDEX when needed. + (Symbol_table::write_section_symbol): Add symtab_xindex + parameter. Change all callers. + (Symbol_table::sized_write_section_symbol): Likewise. Use + SHN_XINDEX when needed. + * symtab.h (class Symbol): Add is_ordinary_shndx_ field. Update + declarations. + (Symbol::shndx): Add is_ordinary parameter. Change all callers. + (Symbol::is_defined): Check is_ordinary. + (Symbol::is_undefined, Symbol::is_weak_undefined): Likewise. + (Symbol::is_absolute, Symbol::is_common): Likewise. + (class Sized_symbol): Update declarations. + (class Symbol_table): Update declarations. + * resolve.cc (Symbol::override_base): Add st_shndx and is_ordinary + parameters. Change all callers. + (Sized_symbol::override): Likewise. + (Symbol_table::override): Likewise. + (symbol_to_bits): Add is_ordinary parameter. Change all callers. + (Symbol_table::resolve): Remove orig_sym parameter. Add st_shndx, + is_ordinary, and orig_st_shndx parameters. Change all callers. + * copy-relocs.cc (Copy_relocs::emit_copy_reloc): Require symbol + to be in an ordinary section. + * dwarf_reader.cc (Sized_dwarf_line_info::symbol_section): Add + object and is_ordinary parameters. Change all callers. + (Sized_dwarf_line_info::read_relocs): Add object parameter. + Change all callers. Don't add undefined or non-ordinary symbols + to reloc_map_. + (Sized_dwarf_line_info::read_line_mappings): Add object parameter. + Change all callers. + * dwarf_reader.h (class Sized_dwarf_line_info): Update + declarations. + * ehframe.cc (Eh_frame::read_fde): Check for ordinary symbol. + * reloc.cc (Sized_relobj::do_read_relocs): Adjust section links. + (Sized_relobj::relocate_sections): Likewise. + * target-reloc.h (scan_relocs): Adjust section symbol index. + (scan_relocatable_relocs): Likewise. + * i386.cc (Scan::local): Check for ordinary symbols. + * sparc.cc (Scan::local): Likewise. + * x86_64.cc (Scan::local): Likewise. + * testsuite/binary_unittest.cc (Sized_binary_test): Update calls + to symbol_section_and_value. + * testsuite/many_sections_test.cc: New file. + * testsuite/Makefile.am (BUILT_SOURCES): Define. + (check_PROGRAMS): Add many_sections_test. + (many_sections_test_SOURCES): Define. + (many_sections_test_DEPENDENCIES): Define. + (many_sections_test_LDFLAGS): Define. + (BUILT_SOURCES): Add many_sections_define.h. + (many_sections_define.h): New target. + (BUILT_SOURCES): Add many_sections_check.h. + (many_sections_check.h): New target. + (check_PROGRAMS): Add many_sections_r_test. + (many_sections_r_test_SOURCES): Define. + (many_sections_r_test_DEPENDENCIES): Define. + (many_sections_r_test_LDFLAGS): Define. + (many_sections_r_test_LDADD): Define. + (many_sections_r_test.o): New target. + * testsuite/Makefile.in: Rebuild. + +2008-04-17 Cary Coutant + + * errors.cc (Errors::info): New function. + (gold_info): New function. + * errors.h (Errors::info): New function. + * gold.h (gold_info): New function. + * object.cc (Input_objects::add_object): Print trace output. + * options.cc (options::parse_set): New function. + (General_options::parse_wrap): Deleted. + (General_options::General_options): Deleted initializer. + * options.h (options::String_set): New typedef. + (options::parse_set): New function. + (DEFINE_set): New macro. + (General_options::wrap): Changed to use DEFINE_set. Changed + callers of any_wrap_symbols and is_wrap_symbol. + (General_options::trace, General_options::trace_symbol): + New options. + (General_options::any_wrap_symbols, General_options::is_wrap_symbol) + (General_options::wrap_symbols_): Deleted. + * symtab.cc (Symbol_table::add_from_object): Print trace output. + +2008-04-17 David S. Miller + + * options.cc (General_options::parse_V): New function. + * options.h: Add entries for -V and -Qy. + +2008-04-17 Ian Lance Taylor + + * common.cc (Symbol_table::allocate_commons): Remove options + parameter. Change caller. + (Symbol_table::do_allocate_commons): Remove options parameter. + Change caller. Just call do_allocate_commons_list twice. + (Symbol_table::do_allocate_commons_list): New function, broken out + of do_allocate_commons. + * common.h (class Allocate_commons_task): Remove options_ field. + Update constructor. + * symtab.cc (Symbol_table::Symbol_table): Initialize + tls_commons_. + (Symbol_table::add_from_object): Put TLS common symbols on + tls_commons_ list. + (Symbol_table::sized_finalize_symbol): Handle STT_TLS symbols + which are IN_OUTPUT_DATA. + * symtab.h (class Symbol_table): Add tls_commons_ field. Update + allocate_commons and do_allocate_commons declarations. Declare + do_allocate_commons_list. + * gold.cc (queue_middle_tasks): Update creation of + Allocate_commons_task to not pass options. + * testsuite/Makefile.am (INCLUDES): Add -I.. . + (TLS_TEST_C_FLAGS): New variable. + (tls_test_c_pic.o): New target. + (tls_test_shared.so): Link in tls_test_c_pic.o. + (tls_test_c_pic_ie.o): New target. + (tls_test_ie_shared.so): Link in tls_test_c_pic_ie.o. + (tls_test_DEPENDENCIES, tls_test_LDADD): Add tls_test_c.o. + (tls_test_c.o): New target. + (tls_pic_test_DEPENDENCIES): Add tls_test_c_pic.o. + (tls_pic_test_LDADD): Likewise. + (tls_shared_gd_to_ie_test_DEPENDENCIES): Add tls_test_c_pic.o. + (tls_shared_gd_to_ie_test_LDADD): Likewise. + (tls_test_c_gnu2.o): New target. + (tls_shared_gnu2_gd_to_ie_test_DEPENDENCIES): Add + tls_test_c_gnu2.o. + (tls_shared_gnu2_gd_to_ie_test_LDADD): Likewise. + (tls_test_gnu2_shared.so): Link in tls_test_c_gnu2.o. + (tls_test_shared_nonpic.so): Link in tls_test_c.o. + * testsuite/tls_test.cc: Include "config.h". + (t_last): Call t11_last. + * testsuite/tls_test.h (t11, t11_last): Declare. + * testsuite/tls_test_c.c: New file. + * testsuite/tls_test_main.cc (thread_routine): Call t11. + * configure.ac: Check for OpenMP support. + * configure, config.in, Makefile.in: Rebuild. + * testsuite/Makefile.in: Rebuild. + +2008-04-16 Cary Coutant + + * i386.cc (Target_i386::define_tls_base_symbol): New function. + (Target_i386::tls_base_symbol_defined_): New field. + (Target_i386::Scan::local): Define _TLS_MODULE_BASE_ symbol. + (Target_i386::Scan::global): Likewise. + * symtab.cc (sized_finalize_symbol): Add check for TLS symbol. + * x86_64.cc (Target_x86_64::define_tls_base_symbol): New function. + (Target_x86_64::tls_base_symbol_defined_): New field. + (Target_x86_64::Scan::local): Define _TLS_MODULE_BASE_ symbol. + (Target_x86_64::Scan::global): Likewise. + +2008-04-16 Cary Coutant + + * symtab.h (Symbol::is_strong_undefined): Removed unused function. + (Symbol::needs_plt_entry): Allow weak undefined symbols. + (Symbol::needs_dynamic_reloc): Allow weak undefined symbols when + building shared libraries. + * testsuite/Makefile.am (weak_undef_nonpic_test): New target. + (weak_undef_file1_nonpic.o, weak_undef_file2_nonpic.o) + (weak_undef_lib_nonpic.so, alt/weak_undef_lib_nonpic.so): New targets. + * testsuite/Makefile.in: Rebuild. + * testsuite/weak_undef.h: New file. + * testsuite/weak_undef_file1.cc: Add extra test cases. + * testsuite/weak_undef_file2.cc: Likewise. + * testsuite/weak_undef_test.cc: Likewise. + +2008-04-16 David S. Miller + + * sparc.cc (Target_sparc::Scan): Change from struct to class. + Add issued_non_pic_error_ field. Declare check_non_pic. + (Target_sparc::Scan::check_non_pic): New function. + (Target_sparc::Scan::local): Call check_non_pic as appropriate. + (Target_sparc::Scan::global): Likewise. + + * configure.ac (FN_PTRS_IN_SO_WITHOUT_PIC): Add sparc64. + * configure: Rebuild. + + * options.h (DEFINE_enable): New macro. + (new_dtags): New enable option. + (initfirst, interpose, loadfltr, nodefaultlib, + nodelete, nodlopen, nodump): New -z options. + * layout.cc (Layout:finish_dynamic_section): If new + dtags enabled, emit DT_RUNPATH. Also, emit a + DT_FLAGS_1 containing any specified -z flags. + +2008-04-16 Ian Lance Taylor + + * copy-relocs.cc: New file. + * copy-relocs.h: New file. + * reloc.cc: Remove Copy_relocs code. + * reloc.h: Likewise. + * reloc-types.h (struct Reloc_types) [both versions]: Add + get_reloc_addend_noerror. + * output.h (class Output_data_reloc): Add + variants of add_global which take an addend which must be zero. + * i386.cc: Include "copy-relocs.h". + (class Target_i386): Change type of copy_relocs_ to variable, + update initializer. + (Target_i386::copy_reloc): Rewrite to pass to Copy_relocs class. + Change all callers. + (Target_i386::do_finalize_sections): Change handling of + copy_relocs_. + * sparc.cc: Include "copy-relocs.h". + (class Target_sparc): Change type of copy_relocs_ to variable, + update initializer. + (Target_sparc::copy_reloc): Rewrite to pass to Copy_relocs class. + Change all callers. + (Target_sparc::do_finalize_sections): Change handling of + copy_relocs_. + * x86_64.cc: Include "copy-relocs.h". + (class Target_x86_64): Change type of copy_relocs_ to variable, + update initializer. + (Target_x86_64::copy_reloc): Rewrite to pass to Copy_relocs + class. Change all callers. + (Target_x86_64::do_finalize_sections): Change handling of + copy_relocs_. + * Makefile.am (CCFILES): Add copy-relocs.cc. + (HFILES): Add copy-relocs.h. + + * Makefile.in, aclocal.m4, testsuite/Makefile.in: Rebuild. + + * testsuite/script_test_4.sh: Permit leading zeroes. + +2008-04-15 Ian Lance Taylor + + * script-sections.cc (Script_sections::create_segments): Use + header_size_adjustment even when there is enough room for the + headers. + * testsuite/script_test_4.sh: New file. + * testsuite/script_test_4.t: New file. + * testsuite/Makefile.am (check_SCRIPTS): Add script_test_4.sh. + (check_DATA): Add script_test_4.stdout. + (MOSTLYCLEANFILES): Likewise. + (script_test_4): New target. + (script_test_4.stdout): New target. + * testsuite/Makefile.in: Rebuild. + + * sparc.cc: Add definitions for Output_data_plt_sparc class + constants. + +2008-04-14 David S. Miller + + * sparc.cc: New file. + * Makefile.am (TARGETSOURCES): Add sparc.cc + (ALL_TARGETOBJS): Add sparc.$(OBJEXT) + * configure.tgt: Document targ_extra_size and + targ_extra_big_endian. Add entries for sparc-* and + sparc64-*. + * configure.ac: Handle targ_extra_size and + targ_extra_big_endian. + * Makefile.in: Rebuild. + * configure: Likewise. + * po/POTFILES.in: Likewise. + * po/gold.pot: Likewise. + +2008-04-14 Ian Lance Taylor + + * layout.cc (Layout::Layout): Initialize sections_are_attached_. + (Layout::get_output_section): Ignore SHF_WRITE and SHF_EXECINSTR + in the name/type/flags to section mapping. Don't call + allocate_output_section. + (Layout::choose_output_section): Change parameter from adjust_name + to is_input_section. Don't permit input sections after sections + are attached to segments. Don't call allocate_output_section. + (Layout::layout_eh_frame): Call update_flags_for_input_section, + not write_enable_output_section. + (Layout::make_output_section): Don't push to + unattached_section_list_ nor call attach_to_segment. Call + attach_section_to_segment if sections are attached. + (Layout::attach_sections_to_segments): New function. + (Layout::attach_section_to_segment): New function. + (Layout::attach_allocated_section_to_segment): Rename from + attach_to_segment. Remove flags parameter. + (Layout::allocate_output_section): Remove function. + (Layout::write_enable_output_section): Remove function. + * layout.h (class Layout): Update for above changes. Add new + field sections_are_attached_. + * output.h (Output_section::update_flags_for_input_section): New + function. + * output.cc (Output_section::add_input_section): Call + update_flags_for_input_section. + * gold.cc (queue_middle_tasks): Call attach_sections_to_segments. + +2008-04-11 Cary Coutant + + * i386.cc (Target_i386::got_mod_index_entry): Restore code previously + thought unnecessary. + * x86_64.cc (Target_x86_64::got_mod_index_entry): Likewise. + +2008-04-11 Ian Lance Taylor + + * output.h (class Output_section_data): Remove inline definition + of set_addralign. + * output.cc (Output_section_data::set_addralign): New function. + +2008-04-11 Cary Coutant + + Add support for TLS descriptors for i386 and x86_64. + * i386.cc (Target_i386::Relocate::tls_desc_gd_to_ie): New function. + (Target_i386::Relocate::tls_desc_gd_to_le): New function. + (Target_i386::Got_type): Add GOT_TYPE_TLS_NOFFSET and + GOT_TYPE_TLS_DESC. + (Target_i386::got_mod_index_entry): Remove unnecessary code. + (Target_i386::Scan::local): Implement R_386_TLS_GOTDESC and + R_386_TLS_DESC_CALL relocations. Fix problem with initial-exec + relocations. + (Target_i386::Scan::global): Fix problem with GD-to-IE relaxation. + Implement R_386_TLS_GOTDESC and R_386_TLS_DESC_CALL relocations; + Fix problem with initial-exec relocations. + (Target_i386::Relocate::relocate_tls): Likewise. + (Target_i386::Relocate::tls_gd_to_ie): Fix problem with GD-to-IE + relaxation. + * output.cc (Output_data_dynamic::Dynamic_entry::write): Add + support for section-plus-offset dynamic table entries. + * output.h (Output_data_dynamic::add_section_plus_offset): New function. + (Output_data_dynamic::Dynamic_entry): Add support for + section-plus-offset dynamic table entries. + (Output_data_dynamic::Classification): Likewise. + (Output_data_dynamic::classification_): Renamed offset_. + * x86_64.cc (Target_x86_64::Relocate::tls_desc_gd_to_ie): New function. + (Target_x86_64::Relocate::tls_desc_gd_to_le): New function. + (Target_x86_64::make_plt_section): New function. + (Target_x86_64::reserve_tlsdesc_entries): New function. + (Output_data_plt_x86_64::Output_data_plt_x86_64): Add new parameter. + (Output_data_plt_x86_64::reserve_tlsdesc_entry): New function. + (Output_data_plt_x86_64::has_tlsdesc_entry): New function. + (Output_data_plt_x86_64::get_tlsdesc_got_offset): New function. + (Output_data_plt_x86_64::get_tlsdesc_plt_offset): New function. + (Output_data_plt_x86_64::tlsdesc_plt_entry): New field. + (Output_data_plt_x86_64::set_final_data_size): Move out of line; + add extra PLT entry for TLS descriptors. + (Output_data_plt_x86_64::got_): New field. + (Output_data_plt_x86_64::tlsdesc_got_offset_): New field. + (Output_data_plt_x86_64::Output_data_plt_x86_64): Initialize new + fields. + (Output_data_plt_x86_64::do_write): Write extra PLT entry for TLS + descriptors. + (Target_x86_64::make_plt_entry): Factor out make_plt_section. + (Target_x86_64::got_mod_index_entry): Remove unnecessary code. + (Target_x86_64::Scan::local): Implement R_386_TLS_GOTDESC and + R_386_TLS_DESC_CALL relocations. + (Target_x86_64::Scan::global): Likewise. + (Target_x86_64::do_finalize_sections): Add dynamic table entries + for TLS descriptors. + (Relocate::relocate_tls): Fix problem with GD-to-IE relaxation. + Implement R_386_TLS_GOTDESC and R_386_TLS_DESC_CALL relocations. + (Target_x86_64::Relocate::tls_gd_to_ie): Fix problem with + GD-to-IE relaxation. + * configure.ac: Export new conditional variables TLS_GNU2_DIALECT + and TLS_DESCRIPTORS. + * Makefile.in: Rebuild. + * configure: Rebuild. + * testsuite/Makefile.am (tls_shared_gd_to_ie_test): New target. + (tls_test_shared2.so): New target. + (tls_shared_gd_to_ie_test_SOURCES): New variable. + (tls_shared_gd_to_ie_test_DEPENDENCIES): New variable. + (tls_shared_gd_to_ie_test_LDFLAGS): New variable. + (tls_shared_gd_to_ie_test_LDADD): New variable. + (tls_shared_gnu2_gd_to_ie_test): New target. + (tls_test_gnu2.o, tls_test_file2_gnu2.o, tls_test_gnu2_shared2.so): + New targets. + (tls_shared_gnu2_gd_to_ie_test_SOURCES): New variable. + (ls_shared_gnu2_gd_to_ie_test_DEPENDENCIES): New variable. + (tls_shared_gnu2_gd_to_ie_test_LDFLAGS): New variable. + (tls_shared_gnu2_gd_to_ie_test_LDADD): New variable. + (tls_shared_gnu2_test): New target. + (tls_test_gnu2_shared.so): New target. + (tls_shared_gnu2_test_SOURCES): New variable. + (tls_shared_gnu2_test_DEPENDENCIES): New variable. + (tls_shared_gnu2_test_LDFLAGS): New variable. + (tls_shared_gnu2_test_LDADD): New variable. + * testsuite/Makefile.in: Rebuild. + * testsuite/Makefile. + +2008-04-11 Ian Lance Taylor + + * testsuite/Makefile.am (justsyms_2r.o): Add dependency on + justsyms.t. + * testsuite/Makefile.in: Rebuild. + + * testsuite/script_test_2a.cc (script_test_string_a): Make 8 bytes + long. + * testsuite/script_test_2.cc (main): Adjust test. + +2008-04-11 David S. Miller + Ian Lance Taylor + + * options.h (General_options): Add entries for '-Y' and + '-relax'. + * options.cc (General_options:finalize): If -Y was used, add those + entries to the library path instead of the default "/lib" and + "/usr/lib". + +2008-04-11 David S. Miller + + * testsuite/justsyms.t: Start at 0x100. + * testsuite/justsyms_1.cc: Adjust justsyms_string assertion. + * testsuite/script_test_2b.cc (script_test_string_b): Make 8 bytes + long. + * testsuite/script_test_2.cc: Adjust string and section length + checks. + +2008-04-09 Ian Lance Taylor + + PR gold/5996 + * script-sections.cc (Sections_element::allocate_to_segment): Add + orphan parameter. + (Output_section_definition::allocate_to_segment): Likewise. + (Orphan_output_section::allocate_to_segment): Likewise. + (Script_sections::attach_sections_using_phdrs_clause): Don't + propagate non-PT_LOAD segments to orphan sections. + * testsuite/Makefile.am (script_test_3.stdout): Generate using + readelf rather than objdump. + * testsuite/script_test_3.sh: Adjust accordingly. Test that + .interp section and PT_INTERP segment are the same size. + * testsuite/Makefile.in: Rebuild. + + * symtab.cc (Symbol_table::add_from_dynobj): Only look for weak + aliases for symbols defined in the same object. + * testsuite/Makefile.am (check_PROGRAMS): Add weak_alias_test. + (weak_alias_test_SOURCES): New variable. + (weak_alias_test_DEPENDENCIES): New variable. + (weak_alias_test_LDFLAGS): New variable. + (weak_alias_test_LDADD): New variable. + (weak_alias_test_1_pic.o, weak_alias_test_1.so): New targets. + (weak_alias_test_2_pic.o, weak_alias_test_2.so): New targets. + (weak_alias_test_3.o): New target. + (weak_alias_test_4_pic.o, weak_alias_test_4.so): New targets. + * testsuite/weak_alias_test_main.cc: New file. + * testsuite/weak_alias_test_1.cc: New file. + * testsuite/weak_alias_test_2.cc: New file. + * testsuite/weak_alias_test_3.cc: New file. + +2008-04-08 Ian Lance Taylor + + * options.h (class General_options): Add --noinhibit-exec option. + * main.cc (main): Check --noinhibit-exec. + + * options.h (class General_options): Define --wrap as a special + option. Add wrap_symbols_ field. + (General_options::any_wrap_symbols): New function. + (General_options::is_wrap_symbol): New function. + * options.cc (General_options::parse_wrap): New function. + (General_options::General_options): Initialize wrap_symbols_. + * symtab.cc (Symbol_table::wrap_symbol): New function. + (Symbol_table::add_from_object): Handle --wrap. + * symtab.h (class Symbol_table): Declare wrap_symbol. + * target.h (Target::wrap_char): New function. + (Target::Target_info): Add wrap_char field. + * i386.cc (Target_i386::i386_info): Initialize wrap_char. + * x86_64.cc (Target_x86_64::x86_64_info): Likewise. + * testsuite/testfile.cc (Target_test::test_target_info): + Likewise. + + * errors.cc (Errors::undefined_symbol): Mention symbol version if + there is one. + + * layout.h (class Layout): Add added_eh_frame_data_ field. + * layout.cc (Layout::Layout): Initialize new field. + (Layout::layout_eh_frame): Don't add eh_frame_data_ to .eh_frame + output section until we find a section we merged successfully. + * object.cc (Sized_relobj::check_eh_frame_flags): Don't require + that the size be non-zero. + + * merge.cc (Object_merge_map::get_output_offset): Remove inline + qualifier. + +2008-04-08 Craig Silverstein + + * configure.ac: Export new conditional variable HAVE_ZLIB. + * testsuite/Makefile.am (flagstest_o_specialfile): Condition + on HAVE_ZLIB. + (flagstest_o_specialfile_and_compress_debug_sections): Likewise. + * configure, Makefile.in, testsuite/Makefile.in: Rebuild. + +2008-04-07 Ian Lance Taylor + + * version.cc (version_string): Set to "1.5". + + * x86_64.cc (Target_x86_64::Scan): Change from struct to class. + Add issued_non_pic_error_ field. Declare check_non_pic. + (Target_x86_64::Scan::check_non_pic): New function. + (Target_x86_64::Scan::local): Call check_non_pic as appropriate. + (Target_x86_64::Scan::global): Likewise. + + * output.cc (Output_reloc::local_section_offset): Add + addend parameter. Change caller. Handle merge sections. + (Output_reloc::symbol_value): Change parameter type from + Address to Addend. Don't add in the result of + local_section_offset, pass down the addend and use the returned + value. + * output.h (class Output_reloc): Add Addend typedef. + Update declarations of local_section_offset and symbol_value. + * testsuite/two_file_test_1.cc (t18): New function. + * testsuite/two_file_test_2.cc (f18): New function. + * testsuite/two_file_test_main.cc (main): Call t18. + * testsuite/two_file_test.h (t18, f18): Declare. + + * configure.ac: Don't test for objdump, c++filt, or readelf. + * testsuite/Makefile.am: Remove READELF and OBJDUMP_AND_CPPFILT + conditionals. + (TEST_READELF): New variable. + (TEST_OBJDUMP, TEST_CXXFILT, TEST_STRIP): New variables. + (check_PROGRAMS): Add two_file_strip_test. + (two_file_strip_test): New target. + (check_PROGRAMS): Add two_file_same_shared_strip_test. + (two_file_same_shared_strip_test_SOURCES): New variable. + (two_file_same_shared_strip_test_DEPENDENCIES): New variable. + (two_file_same_shared_strip_test_LDFLAGS): New variable. + (two_file_same_shared_strip_test_LDADD): New variable. + (two_file_shared_strip.so): New target. + (ver_test_2.syms, ver_test_4.syms): Use TEST_READELF. + (ver_test_5.syms, ver_test_7.syms): Likewise. + (ver_matching_test.stdout): Use TEST_OBJDUMP and TEST_CXXFILT. + (strip_test_3.stdout): Use TEST_OBJDUMP. + * configure, Makefile.in, testsuite/Makefile.in: Rebuild. + +2008-04-04 Cary Coutant + + * symtab.h (Symbol::is_weak_undefined): New function. + (Symbol::is_strong_undefined): New function. + (Symbol::is_absolute): New function. + (Symbol::needs_plt_entry): Exclude weak undefined symbols. + (Symbol::needs_dynamic_reloc): Exclude weak undefined and + absolute symbols. + * testsuite/Makefile.am (check_PROGRAMS): Add weak_undef_test. + (weak_undef_test): New target. + * testsuite/Makefile.in: Rebuild. + * testsuite/weak_undef_file1.cc: New file. + * testsuite/weak_undef_file2.cc: New file. + * testsuite/weak_undef_test.cc: New file. + +2008-04-03 Craig Silverstein + + * compressed_output.h (class Output_compressed_section): Use + unsigned buffer. + * compressed_output.cc (zlib_compress): Use unsigned buffers, + add zlib header. + (zlib_compressed_suffix): Removed. + (Output_compressed_section::set_final_data_size): Use unsigned + buffers. + * testsuite/Makefile.am (flagstest_compress_debug_sections): + Fix linker invocation. + (flagstest_o_specialfile_and_compress_debug_sections): + Likewise. + * testsuite/Makefile.in: Regenerated. + +2008-04-02 David S. Miller + + * dwarf_reader.cc (Sized_dwarf_line_info::read_header_prolog, + Sized_dwarf_line_info::process_one_opcode): Use Swap_unaligned. + +2008-04-02 Craig Silverstein + + * TODO: New file. + +2008-04-02 Ian Lance Taylor + + * fileread.cc (File_read::find_view): Add byteshift and vshifted + parameters. Update for new key type to views_. Change all + callers. + (File_read::read): Adjust for byteshift in returned view. + (File_read::add_view): New function, broken out of + find_and_make_view. + (File_read::make_view): New function, broken out of + find_and_make_view. + (File_read::find_or_make_view): Add offset and aligned + parameters. Rewrite accordingly. Change all callers. + (File_read::get_view): Add offset and aligned parameters. Adjust + for byteshift in return value. + (File_read::get_lasting_view): Likewise. + * fileread.h (class File_read): Update declarations. + (class File_read::View): Add byteshift_ field. Add byteshift to + constructor. Add byteshift method. + * archive.h (Archive::clear_uncached_views): New function. + (Archive::get_view): Add aligned parameter. Change all callers. + * object.h (Object::get_view): Add aligned parameter. Change all + callers. + (Object::get_lasting_view): Likewise. + + * fileread.cc (File_read::release): Don't call clear_views if + there are multiple objects. + * fileread.h (File_read::clear_uncached_views): New function. + * archive.cc (Add_archive_symbols::run): Call clear_uncached_views + on the archive. + +2008-03-31 Cary Coutant + + Add thin archive support. + * archive.cc (Archive::armagt): New const. + (Archive::setup): Remove task parameter and calls to unlock. + (Archive::unlock_nested_archives): New function. + (Archive::read_header): Add nested_off parameter. Change + all callers. + (Archive::interpret_header): Likewise. + (Archive::include_all_members): Change to handle thin + archives. + (Archive::include_member): Likewise. + * archive.h (Archive::Archive): Add new parameters and + initializers. + (Archive::armagt): New const. + (Archive::setup): Remove task parameter. + (Archive::unlock_nested_archives): New function. + (Archive::read_header): Add nested_off parameter. + (Archive::interpret_header): Likewise. + (Archive::Nested_archive_table): New typedef. + (Archive::is_thin_archive_): New field. + (Archive::nested_archives_): New field. + (Archive::options_): New field. + (Archive::dirpath_): New field. + (Archive::task_): New field. + * readsyms.cc (Read_symbols::do_read_symbols): Add check + for thin archives. Pass additional parameters to + Archive::Archive. Unlock the archive file after calling + Archive::setup. + +2008-03-29 Ian Lance Taylor + + * symtab.cc (Symbol_table::do_define_as_constant): Don't force a + version symbol to be local. + * testsuite/ver_test_4.sh: New file. + * testsuite/Makefile.am (check_SCRIPTS): Add ver_test_4.sh. + (check_DATA): Add ver_test_4.syms. + (ver_test_4.syms): New target. + * testsuite/Makefile.in: Rebuild. + + * output.cc + (Output_section::Input_section_sort_entry::has_priority): New + function. + (Output_section::Input_section_sort_entry::match_file_name): New + function. + (Output_section::Input_section_sort_entry::match_section_name): + Remove. + (Output_section::Input_section_sort_entry::match_section_name_prefix): + Remove. + (Output_section::Input_section_sort_entry::match_section_file): + Remove. + (Output_section::Input_section_sort_compare::operator()): Rewrite + using new Input_section_sort_entry functions. Sort crtbegin and + crtend first. Sort sections with no priority before sections with + a priority. + * testsuite/initpri1.c (d3): Check j != 4. + (cd5): New constructor/destructor function. + (main): Check j != 2. + + * symtab.cc (Symbol_table::add_from_object): If we don't use the + new symbol when resolving, don't call set_is_default. + * testsuite/ver_test_7.cc: New file. + * testsuite/ver_test_7.sh: New file. + * testsuite/Makefile.am (ver_test_7.so): New target. + (ver_test_7.o): New target. + (check_SCRIPTS): Add ver_test_7.sh. + (check_DATA): Add ver_test_7.syms. + (ver_test_7.syms): New target. + +2008-03-28 Ian Lance Taylor + + * layout.cc (Layout::layout): If we see an input section with a + name that needs sorting, set the must_sort flag for the output + section. + (Layout::make_output_section): If the name of the output section + indicates that it might require sorting, set the may_sort flag. + * output.h (Output_section::may_sort_attached_input_sections): New + function. + (Output_section::set_may_sort_attached_input_sections): New + function. + (Output_section::must_sort_attached_input_sections): New + function. + (Output_section::set_must_sort_attached_input_sections): New + function. + (class Output_section): Declare Input_section_sort_entry. Define + Input_section_sort_compare. Declare + sort_attached_input_sections. Add new fields: + may_sort_attached_input_sections_, + must_sort_attached_input_sections_, + attached_input_sections_are_sorted_. + * output.cc (Output_section::Output_section): Initialize new + fields. + (Output_section::add_input_section): Add an entry to + input_sections_ if may_sort or must_sort are true. + (Output_section::set_final_data_size): Call + sort_attached_input_sections if necessary. + (Output_section::Input_section_sort_entry): Define new class. + (Output_section::Input_section_sort_compare::operator()): New + function. + (Output_section::sort_attached_input_sections): New function. + * configure.ac: Check whether the compiler supports constructor + priorities. Define a CONSTRUCTOR_PRIORITY automake conditional. + * testsuite/initpri1.c: New file. + * testsuite/Makefile.am (check_PROGRAMS): Add initpri1 if + CONSTRUCTOR_PRIORITY. + (initpri1_SOURCES, initpri1_DEPENDENCIES): New variables. + (initpri1_LDFLAGS): New variable. + * configure, Makefile.in, testsuite/Makefile.in: Rebuild. + +2008-03-27 Ian Lance Taylor + + * common.cc (Sort_commons::operator): Correct sorting algorithm. + * testsuite/common_test_1.c: New file. + * testsuite/Makefile.am (check_PROGRAMS): Add common_test_1. + (common_test_1_SOURCES): New variable. + (common_test_1_DEPENDENCIES): New variable. + (common_test_1_LDFLAGS): New variable. + + * symtab.cc (Symbol_table::add_from_object): Handle saw_undefined_ + and commons_ correctly when NAME/VERSION does not override + NAME/NULL. + * testsuite/ver_test_6.c: New file. + * testsuite/Makefile.am (check_PROGRAMS): Add ver_test_6 + (ver_test_6_SOURCES, ver_test_6_DEPENDENCIES): New variables. + (ver_test_6_LDFLAGS, ver_test_6_LDADD): New variables. + +2008-03-26 Ian Lance Taylor + + * symtab.cc (Symbol_table::add_from_relobj): Don't set the version + of an undefined symbol from a version script. + * testsuite/Makefile.am (ver_test_5.so): New target. + (ver_test_5.o): New target. + (check_SCRIPTS): Add ver_test_5.sh. + (check_DATA): Add ver_test_5.syms. + (ver_test_5.syms): New target. + * testsuite/ver_test_5.cc: New file. + * testsuite/ver_test_5.script: New file. + * testsuite/ver_test_5.sh: New file. + * Makefile.in, testsuite/Makefile.in: Rebuild. + + PR gold/5986 + Fix problems building gold with gcc 4.3.0. + * gold.h (TEMPLATE_ATTRIBUTE_PRINTF_4): Define. + (gold_error_at_location, gold_warning_at_location): Use it. + * configure.ac: Check whether we can compile and use a template + function with a printf attribute. + * x86_64.cc (Target_x86_64::do_code_fill): Swap out a 32-bit value + when jumping over bytes. + * object.cc: Instantiate Object::read_section_data. + * debug.h: Include + * dwarf_reader.cc: Include + * main.cc: Include . + * options.cc: Include . + * output.cc: Include . + * script.cc: Include . + * script.h: Include . + * symtab.cc: Include and . + * target-select.cc: Include . + * version.cc: Include . + * testsuite/testmain.cc: Include . + * configure, config.in: Rebuild. + +2008-03-25 Ian Lance Taylor + + * options.cc: Include "../bfd/bfdver.h". + (options::help): Print bug reporting address. + + * version.cc (print_version): Adjust output for current value of + BFD_VERSION_STRING. + + * NEWS: New file. + + * options.cc (options::help): Print list of supported targets. + * target-select.h: Include . + (class Target_selector): Make machine_, size_, and is_big_endian_ + fields const. Add bfd_name_ and instantiated_target_ fields. + (Target_selector::Target_selector): Add bfd_name parameter. + (Target_selector::recognize): Make non-virtual, call + do_recognize. + (Target_selector::recognize_by_name): Make non-virtual, call + do_recognize_by_name. + (Target_selector::supported_names): New function. + (Target_selector::bfd_name): New function. + (Target_selector::do_instantiate_target): New pure virtual + function. + (Target_selector::do_recognize): New virtual function. + (Target_selector::do_recognize_by_name): New virtual function. + (Target_selector::instantiate_target): New private function. + (supported_target_names): Declare. + * target-select.cc (Target_selector::Target_selector): Update for + new parameter and fields. + (select_target_by_name): Check that the name matches before + calling recognize_by_name. + (supported_target_names): New function. + * i386.cc (class Target_selector_i386): Update Target_selector + constructor call. Remove recognize and recognize_by_name. Add + do_instantiate_target. + * x86_64.cc (class Target_selector_x86_64): Likewise. + * testsuite/testfile.cc (class Target_selector_test): Update for + changes to Target_selector. + + * README: Rewrite, with some notes on unsupported features. + +2008-03-24 Cary Coutant + + * i386.cc (Target_i386::Got_type): New enum declaration. + (Target_i386::Scan::local): Updated callers of Output_data_got + member functions. + (Target_i386::Scan::global): Likewise. + (Target_i386::Relocate::relocate): Likewise. + (Target_i386::Relocate::relocate_tls): Likewise. + * object.h (Got_offset_list): New class. + (Sized_relobj::local_has_got_offset): Added got_type parameter. + (Sized_relobj::local_got_offset): Likewise. + (Sized_relobj::set_local_got_offset): Likewise. + (Sized_relobj::local_has_tls_got_offset): Removed. + (Sized_relobj::local_tls_got_offset): Removed. + (Sized_relobj::set_local_tls_got_offset): Removed. + (Sized_relobj::Local_got_offsets): Changed to store a list of offsets. + * output.cc (Output_data_got::add_global): Added got_type parameter. + (Output_data_got::add_global_with_rel): Likewise. + (Output_data_got::add_global_with_rela): Likewise. + (Output_data_got::add_global_pair_with_rel): New function. + (Output_data_got::add_global_pair_with_rela): New function. + (Output_data_got::add_local): Added got_type parameter. + (Output_data_got::add_local_with_rel): Likewise. + (Output_data_got::add_local_with_rela): Likewise. + (Output_data_got::add_local_pair_with_rel): New function. + (Output_data_got::add_local_pair_with_rela): New function. + (Output_data_got::add_global_tls): Removed. + (Output_data_got::add_global_tls_with_rel): Removed. + (Output_data_got::add_global_tls_with_rela): Removed. + (Output_data_got::add_local_tls): Removed. + (Output_data_got::add_local_tls_with_rel): Removed. + (Output_data_got::add_local_tls_with_rela): Removed. + * output.h (Output_data_got::add_global): Added got_type parameter. + (Output_data_got::add_global_with_rel): Likewise. + (Output_data_got::add_global_with_rela): Likewise. + (Output_data_got::add_global_pair_with_rel): New function. + (Output_data_got::add_global_pair_with_rela): New function. + (Output_data_got::add_local): Added got_type parameter. + (Output_data_got::add_local_with_rel): Likewise. + (Output_data_got::add_local_with_rela): Likewise. + (Output_data_got::add_local_pair_with_rel): New function. + (Output_data_got::add_local_pair_with_rela): New function. + (Output_data_got::add_global_tls): Removed. + (Output_data_got::add_global_tls_with_rel): Removed. + (Output_data_got::add_global_tls_with_rela): Removed. + (Output_data_got::add_local_tls): Removed. + (Output_data_got::add_local_tls_with_rel): Removed. + (Output_data_got::add_local_tls_with_rela): Removed. + * resolve.cc (Symbol::override_base_with_special): Removed + reference to has_got_offset_ field. + * symtab.cc (Symbol::init_fields): Replaced initialization + of got_offset_ with got_offsets_. Removed initialization + of has_got_offset_ + * symtab.h (Symbol::has_got_offset): Aded got_type parameter. + (Symbol::got_offset): Likewise. + (Symbol::set_got_offset): Likewise. + (Symbol::has_tls_got_offset): Removed. + (Symbol::tls_got_offset): Removed. + (Symbol::set_tls_got_offset): Removed. + (Symbol::got_offset_): Removed. + (Symbol::tls_mod_got_offset_): Removed. + (Symbol::tls_pair_got_offset_): Removed. + (Symbol::got_offsets_): New field. + (Symbol::has_got_offset): Removed. + (Symbol::has_tls_mod_got_offset): Removed. + (Symbol::has_tls_pair_got_offset): Removed. + * x86_64.cc (Target_x86_64::Got_type): New enum declaration. + (Target_x86_64::Scan::local): Updated callers of Output_data_got + member functions. + (Target_x86_64::Scan::global): Likewise. + (Target_x86_64::Relocate::relocate): Likewise. + (Target_x86_64::Relocate::relocate_tls): Likewise. + +2008-03-25 Ben Elliston + + * yyscript.y: Fix spelling error in comment. + +2008-03-24 Ian Lance Taylor + + * options.h (class General_options): Define build_id option. + * layout.h (class Layout): Declare write_build_id, create_note, + create_build_id. Add build_id_note_ member. + * layout.cc: Include , , , + "libiberty.h", "md5.h", "sha1.h". + (Layout::Layout): Initialize eh_frame_data_, + eh_frame_hdr_section_, and build_id_note_. + (Layout::finalize): Call create_build_id. + (Layout::create_note): New function, broken out of + Layout::create_gold_note. + (Layout::create_gold_note): Call create_note. + (Layout::create_build_id): New function. + (Layout::write_build_id): New function. + (Close_task_runner::run): Call write_build_id. + + * x86_64.cc: Correct license to GPLv3. + +2008-03-23 Ian Lance Taylor + + * options.cc: Include "demangle.h". + (parse_optional_string): New function. + (parse_long_option): Handle takes_optional_argument. + (parse_short_option): Update dash_z initializer. Handle + takes_optional_argument. + (General_options::General_options): Initialize do_demangle_. + (General_options::finalize): Set do_demangle_. Handle demangling + style. + * options.h (parse_optional_string): Declare. + (struct One_option): Add optional_arg field. Update constructor. + Update call constructor calls. Add takes_optional_argument + function. + (DEFINE_var): Add optional_arg__ parameter. Change all callers. + (DEFINE_optional_string): Define. + (General_options::demangle): Change from DEFINE_bool to + DEFINE_optional_string. + (General_options::no_demangle): New function. + (General_options::do_demangle): New function. + (General_options::set_do_demangle): New function. + (General_options::execstack_status_): Move definition to end of + class definition. + (General_options::static_): Likewise. + (General_options::do_demangle_): New field. + * object.cc (big_endian>::get_symbol_location_info): Call + Options::do_demangle, not Options::demangle. + * symtab.cc (demangle): Likewise. + +2008-03-22 Ian Lance Taylor + + * gold.h: Include and + * options.h: Include . + +2008-03-21 Ian Lance Taylor + + * Added source code to GNU binutils. + +Copyright (C) 2008-2013 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. + +Local Variables: +mode: change-log +left-margin: 8 +fill-column: 74 +version-control: never +End: diff --git a/binutils-2.25/gold/Makefile.am b/binutils-2.25/gold/Makefile.am new file mode 100644 index 00000000..8e2fff10 --- /dev/null +++ b/binutils-2.25/gold/Makefile.am @@ -0,0 +1,363 @@ +## Process this file with automake to generate Makefile.in +# +# Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 +# Free Software Foundation, Inc. +# +# This file 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; see the file COPYING3. If not see +# . +# + +AUTOMAKE_OPTIONS = foreign + +SUBDIRS = po testsuite + +tooldir = $(exec_prefix)/$(target_alias) + +ACLOCAL_AMFLAGS = -I ../bfd -I ../config + +AM_CFLAGS = $(WARN_CFLAGS) $(LFS_CFLAGS) $(RANDOM_SEED_CFLAGS) +AM_CXXFLAGS = $(WARN_CXXFLAGS) $(LFS_CFLAGS) $(RANDOM_SEED_CFLAGS) + +AM_CPPFLAGS = \ + -I$(srcdir) -I$(srcdir)/../include -I$(srcdir)/../elfcpp \ + -DLOCALEDIR="\"$(datadir)/locale\"" \ + -DBINDIR="\"$(bindir)\"" -DTOOLBINDIR="\"$(tooldir)/bin\"" \ + -DTOOLLIBDIR="\"$(tooldir)/lib\"" @INCINTL@ + +LIBIBERTY = ../libiberty/libiberty.a + +if PLUGINS +LIBDL = @DLOPEN_LIBS@ +endif + +if THREADS +THREADSLIB = -lpthread +endif + +AM_YFLAGS = -d + +# Automake 1.10+ disables lex and yacc output file regeneration if +# maintainer mode is disabled. Avoid this. +am__skiplex = +am__skipyacc = + +bin_PROGRAMS = dwp + +noinst_PROGRAMS = ld-new incremental-dump +noinst_LIBRARIES = libgold.a + +CCFILES = \ + archive.cc \ + attributes.cc \ + binary.cc \ + common.cc \ + compressed_output.cc \ + copy-relocs.cc \ + cref.cc \ + defstd.cc \ + descriptors.cc \ + dirsearch.cc \ + dynobj.cc \ + dwarf_reader.cc \ + ehframe.cc \ + errors.cc \ + expression.cc \ + fileread.cc \ + gc.cc \ + gdb-index.cc \ + gold.cc \ + gold-threads.cc \ + icf.cc \ + incremental.cc \ + int_encoding.cc \ + layout.cc \ + mapfile.cc \ + merge.cc \ + nacl.cc \ + object.cc \ + options.cc \ + output.cc \ + parameters.cc \ + plugin.cc \ + readsyms.cc \ + reduced_debug_output.cc \ + reloc.cc \ + resolve.cc \ + script-sections.cc \ + script.cc \ + stringpool.cc \ + symtab.cc \ + target.cc \ + target-select.cc \ + timer.cc \ + version.cc \ + workqueue.cc \ + workqueue-threads.cc + +HFILES = \ + arm-reloc-property.h \ + archive.h \ + attributes.h \ + binary.h \ + common.h \ + compressed_output.h \ + copy-relocs.h \ + cref.h \ + defstd.h \ + dirsearch.h \ + descriptors.h \ + dynobj.h \ + dwarf_reader.h \ + ehframe.h \ + errors.h \ + fileread.h \ + freebsd.h \ + gc.h \ + gdb-index.h \ + gold.h \ + gold-threads.h \ + icf.h \ + int_encoding.h \ + layout.h \ + mapfile.h \ + merge.h \ + nacl.h \ + object.h \ + options.h \ + output.h \ + parameters.h \ + plugin.h \ + readsyms.h \ + reduced_debug_output.h \ + reloc.h \ + reloc-types.h \ + script-c.h \ + script-sections.h \ + script.h \ + stringpool.h \ + symtab.h \ + target.h \ + target-reloc.h \ + target-select.h \ + timer.h \ + tls.h \ + token.h \ + workqueue.h \ + workqueue-internal.h + +YFILES = \ + yyscript.y + +DEFFILES = arm-reloc.def + +EXTRA_DIST = yyscript.c yyscript.h + +TARGETSOURCES = \ + i386.cc x86_64.cc sparc.cc powerpc.cc arm.cc arm-reloc-property.cc tilegx.cc + +ALL_TARGETOBJS = \ + i386.$(OBJEXT) x86_64.$(OBJEXT) sparc.$(OBJEXT) powerpc.$(OBJEXT) \ + arm.$(OBJEXT) arm-reloc-property.$(OBJEXT) tilegx.$(OBJEXT) + +libgold_a_SOURCES = $(CCFILES) $(HFILES) $(YFILES) $(DEFFILES) +libgold_a_LIBADD = $(LIBOBJS) + +sources_var = main.cc +deps_var = $(TARGETOBJS) libgold.a $(LIBIBERTY) $(LIBINTL_DEP) +ldadd_var = $(TARGETOBJS) libgold.a $(LIBIBERTY) $(GOLD_LDADD) $(LIBINTL) \ + $(THREADSLIB) $(LIBDL) +ldflags_var = $(GOLD_LDFLAGS) + +ld_new_SOURCES = $(sources_var) +ld_new_DEPENDENCIES = $(deps_var) +ld_new_LDADD = $(ldadd_var) +ld_new_LDFLAGS = $(ldflags_var) + +EXTRA_ld_new_SOURCES = $(TARGETSOURCES) + +incremental_dump_SOURCES = incremental-dump.cc +incremental_dump_DEPENDENCIES = $(TARGETOBJS) libgold.a $(LIBIBERTY) \ + $(LIBINTL_DEP) +incremental_dump_LDADD = $(TARGETOBJS) libgold.a $(LIBIBERTY) $(LIBINTL) \ + $(THREADSLIB) $(LIBDL) + +dwp_SOURCES = dwp.cc +dwp_DEPENDENCIES = libgold.a $(LIBIBERTY) $(LIBINTL_DEP) +dwp_LDADD = libgold.a $(LIBIBERTY) $(GOLD_LDADD) $(LIBINTL) $(THREADSLIB) \ + $(LIBDL) +dwp_LDFLAGS = $(GOLD_LDFLAGS) + +# Use an explicit dependency for the bison generated header file. +expression.$(OBJEXT): yyscript.h +script-sections.$(OBJEXT): yyscript.h +script.$(OBJEXT): yyscript.h + +# We have to build libgold.a before we run the tests. +check: libgold.a + +.PHONY: install-exec-local + +install-exec-local: ld-new$(EXEEXT) + $(mkinstalldirs) $(DESTDIR)$(bindir) $(DESTDIR)$(tooldir)/bin + n=`echo $(installed_linker) | sed '$(transform)'`; \ + $(INSTALL_PROGRAM) ld-new$(EXEEXT) $(DESTDIR)$(bindir)/$${n}$(EXEEXT); \ + if test "$(bindir)" != "$(tooldir)/bin"; then \ + rm -f $(DESTDIR)$(tooldir)/bin/$(installed_linker)$(EXEEXT); \ + ln $(DESTDIR)$(bindir)/$${n}$(EXEEXT) $(DESTDIR)$(tooldir)/bin/$(installed_linker)$(EXEEXT) >/dev/null 2>/dev/null \ + || $(INSTALL_PROGRAM) ld-new$(EXEEXT) $(DESTDIR)$(tooldir)/bin/$(installed_linker)$(EXEEXT); \ + fi; \ + if test "x$(install_as_default)" = "xyes"; then \ + ld=`echo ld | sed '$(transform)'`; \ + rm -f $(DESTDIR)$(bindir)/$${ld}$(EXEEXT); \ + ln $(DESTDIR)$(bindir)/$${n}$(EXEEXT) $(DESTDIR)$(bindir)/$${ld}$(EXEEXT) >/dev/null 2>/dev/null \ + || $(INSTALL_PROGRAM) ld-new$(EXEEXT) $(DESTDIR)$(bindir)/$${ld}$(EXEEXT); \ + if test "$(bindir)" != "$(tooldir)/bin"; then \ + rm -f $(DESTDIR)$(tooldir)/bin/ld$(EXEEXT); \ + ln $(DESTDIR)$(bindir)/$${n}$(EXEEXT) $(DESTDIR)$(tooldir)/bin/ld$(EXEEXT) >/dev/null 2>/dev/null \ + || $(INSTALL_PROGRAM) ld-new$(EXEEXT) $(DESTDIR)$(tooldir)/bin/ld$(EXEEXT); \ + fi; \ + fi + +# We want install to imply install-info as per GNU standards, despite +# the cygnus option. +install-data-local: install-info + +POTFILES= $(CCFILES) $(HFILES) $(TARGETSOURCES) + +po/POTFILES.in: @MAINT@ Makefile + for f in $(POTFILES); do echo $$f; done | LC_ALL=C sort > tmp \ + && mv tmp $(srcdir)/po/POTFILES.in + +# Bootstrap test support. We use ld-new to build ld1, then use ld1 to +# build ld2. ld1 and ld2 should be identical. ld-new need not be +# identical to ld1, since it was linked with the host linker. + +if GCC +if NATIVE_LINKER + +gcctestdir1/ld: ld-new + test -d gcctestdir1 || mkdir -p gcctestdir1 + rm -f gcctestdir1/ld + (cd gcctestdir1 && $(LN_S) ../ld-new ld) + +ld1_SOURCES = $(sources_var) +ld1_DEPENDENCIES = $(deps_var) gcctestdir1/ld +ld1_LDADD = $(ldadd_var) +ld1_LDFLAGS = -Bgcctestdir1/ + +gcctestdir2/ld: ld1 + test -d gcctestdir2 || mkdir -p gcctestdir2 + rm -f gcctestdir2/ld + (cd gcctestdir2 && $(LN_S) ../ld1 ld) + +ld2_SOURCES = $(sources_var) +ld2_DEPENDENCIES = $(deps_var) gcctestdir2/ld +ld2_LDADD = $(ldadd_var) +ld2_LDFLAGS = -Bgcctestdir2/ + +bootstrap-test: ld2 + rm -f $@ + echo "#!/bin/sh" > $@ + echo "cmp ld1 ld2" >> $@ + chmod +x $@ + +libgold-1-r.o: gcctestdir1/ld libgold.a + gcctestdir1/ld -o $@ -r --whole-archive libgold.a + +ld1_r_SOURCES = $(sources_var) +ld1_r_DEPENDENCIES = libgold-1-r.o $(deps_var) gcctestdir1/ld +ld1_r_LDADD = libgold-1-r.o $(ldadd_var) +ld1_r_LDFLAGS = -Bgcctestdir1/ + +gcctestdir2-r/ld: ld1-r + test -d gcctestdir2-r || mkdir -p gcctestdir2-r + rm -f gcctestdir2-r/ld + (cd gcctestdir2-r && $(LN_S) ../ld1-r ld) + +libgold-2-r.o: gcctestdir2-r/ld libgold.a + gcctestdir2-r/ld -o $@ -r --whole-archive libgold.a + +ld2_r_SOURCES = $(sources_var) +ld2_r_DEPENDENCIES = libgold-2-r.o $(deps_var) gcctestdir2-r/ld +ld2_r_LDADD = libgold-2-r.o $(ldadd_var) +ld2_r_LDFLAGS = -Bgcctestdir2-r/ + +bootstrap-test-r: ld2-r + rm -f $@ + echo "#!/bin/sh" > $@ + echo "cmp ld1-r ld2-r" >> $@ + chmod +x $@ + +check_PROGRAMS = ld1 ld2 ld1-r ld2-r +TESTS = bootstrap-test bootstrap-test-r + +# Verify that changing the number of threads doesn't change the +# treehash computation, by building ld1 and ld3 the same way except +# for the number of threads. However, the build ID should change if +# we change the chunk size for --build-id=tree, so ld4 should be +# different. We run the latter test even if multithreading is unavailable, +# because the treehash can still operate in that mode. +check_PROGRAMS += ld4 +TESTS += bootstrap-test-treehash-chunksize + +gcctestdir3/ld: ld-new + test -d gcctestdir3 || mkdir -p gcctestdir3 + rm -f gcctestdir3/ld + (cd gcctestdir3 && $(LN_S) ../ld-new ld) + +ld3_SOURCES = $(sources_var) +ld3_DEPENDENCIES = $(deps_var) gcctestdir3/ld +ld3_LDADD = $(ldadd_var) +ld3_LDFLAGS = -Bgcctestdir3/ + +gcctestdir4/ld: ld-new + test -d gcctestdir4 || mkdir -p gcctestdir4 + rm -f gcctestdir4/ld + (cd gcctestdir4 && $(LN_S) ../ld-new ld) + +ld4_SOURCES = $(sources_var) +ld4_DEPENDENCIES = $(deps_var) gcctestdir4/ld +ld4_LDADD = $(ldadd_var) +ld4_LDFLAGS = -Bgcctestdir4/ + +ld1_LDFLAGS += -Wl,--build-id=tree -Wl,--build-id-chunk-size-for-treehash=12345 -Wl,--build-id-min-file-size-for-treehash=0 +ld2_LDFLAGS += -Wl,--build-id=tree -Wl,--build-id-chunk-size-for-treehash=12345 -Wl,--build-id-min-file-size-for-treehash=0 +ld3_LDFLAGS += -Wl,--build-id=tree -Wl,--build-id-chunk-size-for-treehash=12345 -Wl,--build-id-min-file-size-for-treehash=0 +ld4_LDFLAGS += -Wl,--build-id=tree -Wl,--build-id-chunk-size-for-treehash=12346 -Wl,--build-id-min-file-size-for-treehash=0 + +if THREADS + +ld1_LDFLAGS += -Wl,--thread-count=3 +ld2_LDFLAGS += -Wl,--thread-count=3 +ld3_LDFLAGS += -Wl,--thread-count=13 +ld4_LDFLAGS += -Wl,--thread-count=3 +check_PROGRAMS += ld3 +TESTS += bootstrap-test-treehash-chunksize + +bootstrap-test-treehash: ld1 ld3 + rm -f $@ + echo "#!/bin/sh" > $@ + echo "cmp ld1 ld3" >> $@ + chmod +x $@ + +endif + +bootstrap-test-treehash-chunksize: ld1 ld4 + rm -f $@ + echo "#!/bin/sh" > $@ + echo "cmp ld1 ld4 | grep ." >> $@ + chmod +x $@ + +endif +endif diff --git a/binutils-2.25/gold/Makefile.in b/binutils-2.25/gold/Makefile.in new file mode 100644 index 00000000..3bd9fae2 --- /dev/null +++ b/binutils-2.25/gold/Makefile.in @@ -0,0 +1,1385 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +# +# Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 +# Free Software Foundation, Inc. +# +# This file 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; see the file COPYING3. If not see +# . +# + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +target_triplet = @target@ +bin_PROGRAMS = dwp$(EXEEXT) +noinst_PROGRAMS = ld-new$(EXEEXT) incremental-dump$(EXEEXT) +@GCC_TRUE@@NATIVE_LINKER_TRUE@check_PROGRAMS = ld1$(EXEEXT) \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ ld2$(EXEEXT) ld1-r$(EXEEXT) \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ ld2-r$(EXEEXT) ld4$(EXEEXT) \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(am__EXEEXT_1) +@GCC_TRUE@@NATIVE_LINKER_TRUE@@THREADS_TRUE@am__append_1 = -Wl,--thread-count=3 +@GCC_TRUE@@NATIVE_LINKER_TRUE@@THREADS_TRUE@am__append_2 = -Wl,--thread-count=3 +@GCC_TRUE@@NATIVE_LINKER_TRUE@@THREADS_TRUE@am__append_3 = -Wl,--thread-count=13 +@GCC_TRUE@@NATIVE_LINKER_TRUE@@THREADS_TRUE@am__append_4 = -Wl,--thread-count=3 +@GCC_TRUE@@NATIVE_LINKER_TRUE@@THREADS_TRUE@am__append_5 = ld3 +@GCC_TRUE@@NATIVE_LINKER_TRUE@@THREADS_TRUE@am__append_6 = bootstrap-test-treehash-chunksize +subdir = . +DIST_COMMON = NEWS README ChangeLog $(srcdir)/Makefile.in \ + $(srcdir)/Makefile.am $(top_srcdir)/configure \ + $(am__configure_deps) $(srcdir)/config.in \ + $(srcdir)/../mkinstalldirs $(top_srcdir)/po/Make-in ffsll.c \ + ftruncate.c pread.c mremap.c yyscript.h yyscript.c \ + $(srcdir)/../depcomp $(srcdir)/../ylwrap +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 \ + $(top_srcdir)/../config/po.m4 \ + $(top_srcdir)/../config/progtest.m4 \ + $(top_srcdir)/../config/zlib.m4 \ + $(top_srcdir)/../bfd/warning.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = po/Makefile.in +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +AR = ar +ARFLAGS = cru +libgold_a_AR = $(AR) $(ARFLAGS) +libgold_a_DEPENDENCIES = $(LIBOBJS) +am__objects_1 = archive.$(OBJEXT) attributes.$(OBJEXT) \ + binary.$(OBJEXT) common.$(OBJEXT) compressed_output.$(OBJEXT) \ + copy-relocs.$(OBJEXT) cref.$(OBJEXT) defstd.$(OBJEXT) \ + descriptors.$(OBJEXT) dirsearch.$(OBJEXT) dynobj.$(OBJEXT) \ + dwarf_reader.$(OBJEXT) ehframe.$(OBJEXT) errors.$(OBJEXT) \ + expression.$(OBJEXT) fileread.$(OBJEXT) gc.$(OBJEXT) \ + gdb-index.$(OBJEXT) gold.$(OBJEXT) gold-threads.$(OBJEXT) \ + icf.$(OBJEXT) incremental.$(OBJEXT) int_encoding.$(OBJEXT) \ + layout.$(OBJEXT) mapfile.$(OBJEXT) merge.$(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) \ + $(am__objects_3) $(am__objects_2) +libgold_a_OBJECTS = $(am_libgold_a_OBJECTS) +am__installdirs = "$(DESTDIR)$(bindir)" +@GCC_TRUE@@NATIVE_LINKER_TRUE@@THREADS_TRUE@am__EXEEXT_1 = \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@@THREADS_TRUE@ ld3$(EXEEXT) +PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS) +am_dwp_OBJECTS = dwp.$(OBJEXT) +dwp_OBJECTS = $(am_dwp_OBJECTS) +am__DEPENDENCIES_1 = +dwp_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(dwp_LDFLAGS) \ + $(LDFLAGS) -o $@ +am_incremental_dump_OBJECTS = incremental-dump.$(OBJEXT) +incremental_dump_OBJECTS = $(am_incremental_dump_OBJECTS) +am__objects_4 = main.$(OBJEXT) +am_ld_new_OBJECTS = $(am__objects_4) +ld_new_OBJECTS = $(am_ld_new_OBJECTS) +am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) libgold.a $(LIBIBERTY) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +ld_new_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(ld_new_LDFLAGS) \ + $(LDFLAGS) -o $@ +@GCC_TRUE@@NATIVE_LINKER_TRUE@am_ld1_OBJECTS = $(am__objects_4) +ld1_OBJECTS = $(am_ld1_OBJECTS) +ld1_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(ld1_LDFLAGS) \ + $(LDFLAGS) -o $@ +@GCC_TRUE@@NATIVE_LINKER_TRUE@am_ld1_r_OBJECTS = $(am__objects_4) +ld1_r_OBJECTS = $(am_ld1_r_OBJECTS) +ld1_r_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(ld1_r_LDFLAGS) \ + $(LDFLAGS) -o $@ +@GCC_TRUE@@NATIVE_LINKER_TRUE@am_ld2_OBJECTS = $(am__objects_4) +ld2_OBJECTS = $(am_ld2_OBJECTS) +ld2_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(ld2_LDFLAGS) \ + $(LDFLAGS) -o $@ +@GCC_TRUE@@NATIVE_LINKER_TRUE@am_ld2_r_OBJECTS = $(am__objects_4) +ld2_r_OBJECTS = $(am_ld2_r_OBJECTS) +ld2_r_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(ld2_r_LDFLAGS) \ + $(LDFLAGS) -o $@ +@GCC_TRUE@@NATIVE_LINKER_TRUE@am_ld3_OBJECTS = $(am__objects_4) +ld3_OBJECTS = $(am_ld3_OBJECTS) +ld3_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(ld3_LDFLAGS) \ + $(LDFLAGS) -o $@ +@GCC_TRUE@@NATIVE_LINKER_TRUE@am_ld4_OBJECTS = $(am__objects_4) +ld4_OBJECTS = $(am_ld4_OBJECTS) +ld4_LINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(ld4_LDFLAGS) \ + $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ +depcomp = $(SHELL) $(top_srcdir)/../depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +@MAINTAINER_MODE_FALSE@am__skipyacc = test -f $@ || +YACCCOMPILE = $(YACC) $(YFLAGS) $(AM_YFLAGS) +YLWRAP = $(top_srcdir)/../ylwrap +SOURCES = $(libgold_a_SOURCES) $(dwp_SOURCES) \ + $(incremental_dump_SOURCES) $(ld_new_SOURCES) \ + $(EXTRA_ld_new_SOURCES) $(ld1_SOURCES) $(ld1_r_SOURCES) \ + $(ld2_SOURCES) $(ld2_r_SOURCES) $(ld3_SOURCES) $(ld4_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + check check-html recheck recheck-html +ETAGS = etags +CTAGS = ctags +am__tty_colors = \ +red=; grn=; lgn=; blu=; std= +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +# Restructured Text title and section. +am__rst_title = sed 's/.*/ & /;h;s/./=/g;p;x;p;g;p;s/.*//' +am__rst_section = sed 'p;s/./=/g;p;g' +# Put stdin (possibly several lines separated by ". ") in a box. +am__text_box = $(AWK) '{ \ + n = split($$0, lines, "\\. "); max = 0; \ + for (i = 1; i <= n; ++i) \ + if (max < length(lines[i])) \ + max = length(lines[i]); \ + for (i = 0; i < max; ++i) line = line "="; \ + print line; \ + for (i = 1; i <= n; ++i) if (lines[i]) print lines[i];\ + print line; \ +}' +# Solaris 10 'make', and several other traditional 'make' implementations, +# pass "-e" to $(SHELL). This contradicts POSIX. Work around the problem +# by disabling -e (using the XSI extension "set +e") if it's set. +am__sh_e_setup = case $$- in *e*) set +e;; esac +# To be inserted before the command running the test. Creates the +# directory for the log if needed. Stores in $dir the directory +# containing $f, in $tst the test, in $log the log, and passes +# TESTS_ENVIRONMENT. Save and restore TERM around use of +# TESTS_ENVIRONMENT, in case that unsets it. +am__check_pre = \ +$(am__sh_e_setup); \ +$(am__vpath_adj_setup) $(am__vpath_adj) \ +srcdir=$(srcdir); export srcdir; \ +rm -f $@-t; \ +trap 'st=$$?; rm -f '\''$(abs_builddir)/$@-t'\''; (exit $$st); exit $$st' \ + 1 2 13 15; \ +am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`; \ +test "x$$am__odir" = x. || $(MKDIR_P) "$$am__odir" || exit $$?; \ +if test -f "./$$f"; then dir=./; \ +elif test -f "$$f"; then dir=; \ +else dir="$(srcdir)/"; fi; \ +tst=$$dir$$f; log='$@'; __SAVED_TERM=$$TERM; \ +$(TESTS_ENVIRONMENT) +RECHECK_LOGS = $(TEST_LOGS) +TEST_SUITE_LOG = test-suite.log +TEST_SUITE_HTML = $(TEST_SUITE_LOG:.log=.html) +TEST_EXTENSIONS = @EXEEXT@ .test +LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS) +am__test_logs1 = $(TESTS:=.log) +am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log) +TEST_LOGS = $(am__test_logs2:.test.log=.log) +TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \ + $(TEST_LOG_FLAGS) +TEST_LOGS_TMP = $(TEST_LOGS:.log=.log-t) +DIST_SUBDIRS = $(SUBDIRS) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CATALOGS = @CATALOGS@ +CATOBJEXT = @CATOBJEXT@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DATADIRNAME = @DATADIRNAME@ +DEFAULT_TARGET = @DEFAULT_TARGET@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLOPEN_LIBS = @DLOPEN_LIBS@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +GENCAT = @GENCAT@ +GMSGFMT = @GMSGFMT@ +GOLD_LDADD = @GOLD_LDADD@ +GOLD_LDFLAGS = @GOLD_LDFLAGS@ +GREP = @GREP@ +INCINTL = @INCINTL@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INSTOBJEXT = @INSTOBJEXT@ +LDFLAGS = @LDFLAGS@ +LFS_CFLAGS = @LFS_CFLAGS@ +LIBINTL = @LIBINTL@ +LIBINTL_DEP = @LIBINTL_DEP@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MERGE_CONSTANTS_FLAG = @MERGE_CONSTANTS_FLAG@ +MKDIR_P = @MKDIR_P@ +MKINSTALLDIRS = @MKINSTALLDIRS@ +MSGFMT = @MSGFMT@ +MSGMERGE = @MSGMERGE@ +NM = @NM@ +NO_WERROR = @NO_WERROR@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +POSUB = @POSUB@ +RANDOM_SEED_CFLAGS = @RANDOM_SEED_CFLAGS@ +RANLIB = @RANLIB@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TARGETOBJS = @TARGETOBJS@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +WARN_CFLAGS = @WARN_CFLAGS@ +WARN_CXXFLAGS = @WARN_CXXFLAGS@ +XGETTEXT = @XGETTEXT@ +YACC = @YACC@ +YFLAGS = @YFLAGS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_as_default = @install_as_default@ +install_sh = @install_sh@ +installed_linker = @installed_linker@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target = @target@ +target_alias = @target_alias@ +target_cpu = @target_cpu@ +target_os = @target_os@ +target_vendor = @target_vendor@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +AUTOMAKE_OPTIONS = foreign +SUBDIRS = po testsuite +tooldir = $(exec_prefix)/$(target_alias) +ACLOCAL_AMFLAGS = -I ../bfd -I ../config +AM_CFLAGS = $(WARN_CFLAGS) $(LFS_CFLAGS) $(RANDOM_SEED_CFLAGS) +AM_CXXFLAGS = $(WARN_CXXFLAGS) $(LFS_CFLAGS) $(RANDOM_SEED_CFLAGS) +AM_CPPFLAGS = \ + -I$(srcdir) -I$(srcdir)/../include -I$(srcdir)/../elfcpp \ + -DLOCALEDIR="\"$(datadir)/locale\"" \ + -DBINDIR="\"$(bindir)\"" -DTOOLBINDIR="\"$(tooldir)/bin\"" \ + -DTOOLLIBDIR="\"$(tooldir)/lib\"" @INCINTL@ + +LIBIBERTY = ../libiberty/libiberty.a +@PLUGINS_TRUE@LIBDL = @DLOPEN_LIBS@ +@THREADS_TRUE@THREADSLIB = -lpthread +AM_YFLAGS = -d + +# Automake 1.10+ disables lex and yacc output file regeneration if +# maintainer mode is disabled. Avoid this. +am__skiplex = +am__skipyacc = +noinst_LIBRARIES = libgold.a +CCFILES = \ + archive.cc \ + attributes.cc \ + binary.cc \ + common.cc \ + compressed_output.cc \ + copy-relocs.cc \ + cref.cc \ + defstd.cc \ + descriptors.cc \ + dirsearch.cc \ + dynobj.cc \ + dwarf_reader.cc \ + ehframe.cc \ + errors.cc \ + expression.cc \ + fileread.cc \ + gc.cc \ + gdb-index.cc \ + gold.cc \ + gold-threads.cc \ + icf.cc \ + incremental.cc \ + int_encoding.cc \ + layout.cc \ + mapfile.cc \ + merge.cc \ + nacl.cc \ + object.cc \ + options.cc \ + output.cc \ + parameters.cc \ + plugin.cc \ + readsyms.cc \ + reduced_debug_output.cc \ + reloc.cc \ + resolve.cc \ + script-sections.cc \ + script.cc \ + stringpool.cc \ + symtab.cc \ + target.cc \ + target-select.cc \ + timer.cc \ + version.cc \ + workqueue.cc \ + workqueue-threads.cc + +HFILES = \ + arm-reloc-property.h \ + archive.h \ + attributes.h \ + binary.h \ + common.h \ + compressed_output.h \ + copy-relocs.h \ + cref.h \ + defstd.h \ + dirsearch.h \ + descriptors.h \ + dynobj.h \ + dwarf_reader.h \ + ehframe.h \ + errors.h \ + fileread.h \ + freebsd.h \ + gc.h \ + gdb-index.h \ + gold.h \ + gold-threads.h \ + icf.h \ + int_encoding.h \ + layout.h \ + mapfile.h \ + merge.h \ + nacl.h \ + object.h \ + options.h \ + output.h \ + parameters.h \ + plugin.h \ + readsyms.h \ + reduced_debug_output.h \ + reloc.h \ + reloc-types.h \ + script-c.h \ + script-sections.h \ + script.h \ + stringpool.h \ + symtab.h \ + target.h \ + target-reloc.h \ + target-select.h \ + timer.h \ + tls.h \ + token.h \ + workqueue.h \ + workqueue-internal.h + +YFILES = \ + yyscript.y + +DEFFILES = arm-reloc.def +EXTRA_DIST = yyscript.c yyscript.h +TARGETSOURCES = \ + i386.cc x86_64.cc sparc.cc powerpc.cc arm.cc arm-reloc-property.cc tilegx.cc + +ALL_TARGETOBJS = \ + i386.$(OBJEXT) x86_64.$(OBJEXT) sparc.$(OBJEXT) powerpc.$(OBJEXT) \ + arm.$(OBJEXT) arm-reloc-property.$(OBJEXT) tilegx.$(OBJEXT) + +libgold_a_SOURCES = $(CCFILES) $(HFILES) $(YFILES) $(DEFFILES) +libgold_a_LIBADD = $(LIBOBJS) +sources_var = main.cc +deps_var = $(TARGETOBJS) libgold.a $(LIBIBERTY) $(LIBINTL_DEP) +ldadd_var = $(TARGETOBJS) libgold.a $(LIBIBERTY) $(GOLD_LDADD) $(LIBINTL) \ + $(THREADSLIB) $(LIBDL) + +ldflags_var = $(GOLD_LDFLAGS) +ld_new_SOURCES = $(sources_var) +ld_new_DEPENDENCIES = $(deps_var) +ld_new_LDADD = $(ldadd_var) +ld_new_LDFLAGS = $(ldflags_var) +EXTRA_ld_new_SOURCES = $(TARGETSOURCES) +incremental_dump_SOURCES = incremental-dump.cc +incremental_dump_DEPENDENCIES = $(TARGETOBJS) libgold.a $(LIBIBERTY) \ + $(LIBINTL_DEP) + +incremental_dump_LDADD = $(TARGETOBJS) libgold.a $(LIBIBERTY) $(LIBINTL) \ + $(THREADSLIB) $(LIBDL) + +dwp_SOURCES = dwp.cc +dwp_DEPENDENCIES = libgold.a $(LIBIBERTY) $(LIBINTL_DEP) +dwp_LDADD = libgold.a $(LIBIBERTY) $(GOLD_LDADD) $(LIBINTL) $(THREADSLIB) \ + $(LIBDL) + +dwp_LDFLAGS = $(GOLD_LDFLAGS) +POTFILES = $(CCFILES) $(HFILES) $(TARGETSOURCES) +@GCC_TRUE@@NATIVE_LINKER_TRUE@ld1_SOURCES = $(sources_var) +@GCC_TRUE@@NATIVE_LINKER_TRUE@ld1_DEPENDENCIES = $(deps_var) gcctestdir1/ld +@GCC_TRUE@@NATIVE_LINKER_TRUE@ld1_LDADD = $(ldadd_var) +@GCC_TRUE@@NATIVE_LINKER_TRUE@ld1_LDFLAGS = -Bgcctestdir1/ \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ -Wl,--build-id=tree \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ -Wl,--build-id-chunk-size-for-treehash=12345 \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ -Wl,--build-id-min-file-size-for-treehash=0 \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(am__append_1) +@GCC_TRUE@@NATIVE_LINKER_TRUE@ld2_SOURCES = $(sources_var) +@GCC_TRUE@@NATIVE_LINKER_TRUE@ld2_DEPENDENCIES = $(deps_var) gcctestdir2/ld +@GCC_TRUE@@NATIVE_LINKER_TRUE@ld2_LDADD = $(ldadd_var) +@GCC_TRUE@@NATIVE_LINKER_TRUE@ld2_LDFLAGS = -Bgcctestdir2/ \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ -Wl,--build-id=tree \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ -Wl,--build-id-chunk-size-for-treehash=12345 \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ -Wl,--build-id-min-file-size-for-treehash=0 \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(am__append_2) +@GCC_TRUE@@NATIVE_LINKER_TRUE@ld1_r_SOURCES = $(sources_var) +@GCC_TRUE@@NATIVE_LINKER_TRUE@ld1_r_DEPENDENCIES = libgold-1-r.o $(deps_var) gcctestdir1/ld +@GCC_TRUE@@NATIVE_LINKER_TRUE@ld1_r_LDADD = libgold-1-r.o $(ldadd_var) +@GCC_TRUE@@NATIVE_LINKER_TRUE@ld1_r_LDFLAGS = -Bgcctestdir1/ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ld2_r_SOURCES = $(sources_var) +@GCC_TRUE@@NATIVE_LINKER_TRUE@ld2_r_DEPENDENCIES = libgold-2-r.o $(deps_var) gcctestdir2-r/ld +@GCC_TRUE@@NATIVE_LINKER_TRUE@ld2_r_LDADD = libgold-2-r.o $(ldadd_var) +@GCC_TRUE@@NATIVE_LINKER_TRUE@ld2_r_LDFLAGS = -Bgcctestdir2-r/ +@GCC_TRUE@@NATIVE_LINKER_TRUE@TESTS = bootstrap-test bootstrap-test-r \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ bootstrap-test-treehash-chunksize \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(am__append_6) +@GCC_TRUE@@NATIVE_LINKER_TRUE@ld3_SOURCES = $(sources_var) +@GCC_TRUE@@NATIVE_LINKER_TRUE@ld3_DEPENDENCIES = $(deps_var) gcctestdir3/ld +@GCC_TRUE@@NATIVE_LINKER_TRUE@ld3_LDADD = $(ldadd_var) +@GCC_TRUE@@NATIVE_LINKER_TRUE@ld3_LDFLAGS = -Bgcctestdir3/ \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ -Wl,--build-id=tree \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ -Wl,--build-id-chunk-size-for-treehash=12345 \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ -Wl,--build-id-min-file-size-for-treehash=0 \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(am__append_3) +@GCC_TRUE@@NATIVE_LINKER_TRUE@ld4_SOURCES = $(sources_var) +@GCC_TRUE@@NATIVE_LINKER_TRUE@ld4_DEPENDENCIES = $(deps_var) gcctestdir4/ld +@GCC_TRUE@@NATIVE_LINKER_TRUE@ld4_LDADD = $(ldadd_var) +@GCC_TRUE@@NATIVE_LINKER_TRUE@ld4_LDFLAGS = -Bgcctestdir4/ \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ -Wl,--build-id=tree \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ -Wl,--build-id-chunk-size-for-treehash=12346 \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ -Wl,--build-id-min-file-size-for-treehash=0 \ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ $(am__append_4) +all: config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +.SUFFIXES: +.SUFFIXES: .c .cc .html .log .o .obj .test .test$(EXEEXT) .y +am--refresh: + @: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): + +config.h: stamp-h1 + @if test ! -f $@; then \ + rm -f stamp-h1; \ + $(MAKE) $(AM_MAKEFLAGS) stamp-h1; \ + else :; fi + +stamp-h1: $(srcdir)/config.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status config.h +$(srcdir)/config.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) + rm -f stamp-h1 + touch $@ + +distclean-hdr: + -rm -f config.h stamp-h1 +po/Makefile.in: $(top_builddir)/config.status $(top_srcdir)/po/Make-in + cd $(top_builddir) && $(SHELL) ./config.status $@ + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +yyscript.h: yyscript.c + @if test ! -f $@; then \ + rm -f yyscript.c; \ + $(MAKE) $(AM_MAKEFLAGS) yyscript.c; \ + else :; fi +libgold.a: $(libgold_a_OBJECTS) $(libgold_a_DEPENDENCIES) + -rm -f libgold.a + $(libgold_a_AR) libgold.a $(libgold_a_OBJECTS) $(libgold_a_LIBADD) + $(RANLIB) libgold.a +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) + +clean-checkPROGRAMS: + -test -z "$(check_PROGRAMS)" || rm -f $(check_PROGRAMS) + +clean-noinstPROGRAMS: + -test -z "$(noinst_PROGRAMS)" || rm -f $(noinst_PROGRAMS) +dwp$(EXEEXT): $(dwp_OBJECTS) $(dwp_DEPENDENCIES) + @rm -f dwp$(EXEEXT) + $(dwp_LINK) $(dwp_OBJECTS) $(dwp_LDADD) $(LIBS) +incremental-dump$(EXEEXT): $(incremental_dump_OBJECTS) $(incremental_dump_DEPENDENCIES) + @rm -f incremental-dump$(EXEEXT) + $(CXXLINK) $(incremental_dump_OBJECTS) $(incremental_dump_LDADD) $(LIBS) +ld-new$(EXEEXT): $(ld_new_OBJECTS) $(ld_new_DEPENDENCIES) + @rm -f ld-new$(EXEEXT) + $(ld_new_LINK) $(ld_new_OBJECTS) $(ld_new_LDADD) $(LIBS) +ld1$(EXEEXT): $(ld1_OBJECTS) $(ld1_DEPENDENCIES) + @rm -f ld1$(EXEEXT) + $(ld1_LINK) $(ld1_OBJECTS) $(ld1_LDADD) $(LIBS) +ld1-r$(EXEEXT): $(ld1_r_OBJECTS) $(ld1_r_DEPENDENCIES) + @rm -f ld1-r$(EXEEXT) + $(ld1_r_LINK) $(ld1_r_OBJECTS) $(ld1_r_LDADD) $(LIBS) +ld2$(EXEEXT): $(ld2_OBJECTS) $(ld2_DEPENDENCIES) + @rm -f ld2$(EXEEXT) + $(ld2_LINK) $(ld2_OBJECTS) $(ld2_LDADD) $(LIBS) +ld2-r$(EXEEXT): $(ld2_r_OBJECTS) $(ld2_r_DEPENDENCIES) + @rm -f ld2-r$(EXEEXT) + $(ld2_r_LINK) $(ld2_r_OBJECTS) $(ld2_r_LDADD) $(LIBS) +ld3$(EXEEXT): $(ld3_OBJECTS) $(ld3_DEPENDENCIES) + @rm -f ld3$(EXEEXT) + $(ld3_LINK) $(ld3_OBJECTS) $(ld3_LDADD) $(LIBS) +ld4$(EXEEXT): $(ld4_OBJECTS) $(ld4_DEPENDENCIES) + @rm -f ld4$(EXEEXT) + $(ld4_LINK) $(ld4_OBJECTS) $(ld4_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/ffsll.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/ftruncate.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/mremap.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/pread.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/archive.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm-reloc-property.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arm.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/attributes.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/binary.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/compressed_output.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/copy-relocs.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cref.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/defstd.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/descriptors.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dirsearch.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwarf_reader.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dwp.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dynobj.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ehframe.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/errors.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/expression.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fileread.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gdb-index.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gold-threads.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gold.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/i386.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/icf.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/incremental-dump.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/incremental.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/int_encoding.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/layout.Po@am__quote@ +@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@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/parameters.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/powerpc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readsyms.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reduced_debug_output.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reloc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resolve.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script-sections.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/script.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sparc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stringpool.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/symtab.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/target-select.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/target.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tilegx.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/timer.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/workqueue-threads.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/workqueue.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/x86_64.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/yyscript.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.cc.o: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.y.c: + $(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h $*.h y.output $*.output -- $(YACCCOMPILE) + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) config.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) config.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) config.in $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) config.in $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +# To be appended to the command running the test. Handle the stdout +# and stderr redirection, and catch the exit status. +am__check_post = \ +>$@-t 2>&1; \ +estatus=$$?; \ +if test -n '$(DISABLE_HARD_ERRORS)' \ + && test $$estatus -eq 99; then \ + estatus=1; \ +fi; \ +TERM=$$__SAVED_TERM; export TERM; \ +$(am__tty_colors); \ +xfailed=PASS; \ +case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \ + xfailed=XFAIL;; \ +esac; \ +case $$estatus:$$xfailed in \ + 0:XFAIL) col=$$red; res=XPASS;; \ + 0:*) col=$$grn; res=PASS ;; \ + 77:*) col=$$blu; res=SKIP ;; \ + 99:*) col=$$red; res=FAIL ;; \ + *:XFAIL) col=$$lgn; res=XFAIL;; \ + *:*) col=$$red; res=FAIL ;; \ +esac; \ +echo "$${col}$$res$${std}: $$f"; \ +echo "$$res: $$f (exit: $$estatus)" | \ + $(am__rst_section) >$@; \ +cat $@-t >>$@; \ +rm -f $@-t + +$(TEST_SUITE_LOG): $(TEST_LOGS) + @$(am__sh_e_setup); \ + list='$(TEST_LOGS)'; \ + results=`for f in $$list; do \ + read line < $$f && echo "$$line" || echo FAIL; \ + done`; \ + all=`echo "$$results" | sed '/^$$/d' | wc -l | sed -e 's/^[ ]*//'`; \ + fail=`echo "$$results" | grep -c '^FAIL'`; \ + pass=`echo "$$results" | grep -c '^PASS'`; \ + skip=`echo "$$results" | grep -c '^SKIP'`; \ + xfail=`echo "$$results" | grep -c '^XFAIL'`; \ + xpass=`echo "$$results" | grep -c '^XPASS'`; \ + failures=`expr $$fail + $$xpass`; \ + all=`expr $$all - $$skip`; \ + if test "$$all" -eq 1; then tests=test; All=; \ + else tests=tests; All="All "; fi; \ + case fail=$$fail:xpass=$$xpass:xfail=$$xfail in \ + fail=0:xpass=0:xfail=0) \ + msg="$$All$$all $$tests passed. "; \ + exit=true;; \ + fail=0:xpass=0:xfail=*) \ + msg="$$All$$all $$tests behaved as expected"; \ + if test "$$xfail" -eq 1; then xfailures=failure; \ + else xfailures=failures; fi; \ + msg="$$msg ($$xfail expected $$xfailures). "; \ + exit=true;; \ + fail=*:xpass=0:xfail=*) \ + msg="$$fail of $$all $$tests failed. "; \ + exit=false;; \ + fail=*:xpass=*:xfail=*) \ + msg="$$failures of $$all $$tests did not behave as expected"; \ + if test "$$xpass" -eq 1; then xpasses=pass; \ + else xpasses=passes; fi; \ + msg="$$msg ($$xpass unexpected $$xpasses). "; \ + exit=false;; \ + *) \ + echo >&2 "incorrect case"; exit 4;; \ + esac; \ + if test "$$skip" -ne 0; then \ + if test "$$skip" -eq 1; then \ + msg="$$msg($$skip test was not run). "; \ + else \ + msg="$$msg($$skip tests were not run). "; \ + fi; \ + fi; \ + { \ + echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \ + $(am__rst_title); \ + echo "$$msg"; \ + echo; \ + echo ".. contents:: :depth: 2"; \ + echo; \ + for f in $$list; do \ + read line < $$f; \ + case $$line in \ + PASS:*|XFAIL:*);; \ + *) echo; cat $$f;; \ + esac; \ + done; \ + } >$(TEST_SUITE_LOG).tmp; \ + mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \ + if test "$$failures" -ne 0; then \ + msg="$${msg}See $(subdir)/$(TEST_SUITE_LOG). "; \ + if test -n "$(PACKAGE_BUGREPORT)"; then \ + msg="$${msg}Please report to $(PACKAGE_BUGREPORT). "; \ + fi; \ + fi; \ + test x"$$VERBOSE" = x || $$exit || cat $(TEST_SUITE_LOG); \ + $(am__tty_colors); \ + if $$exit; then \ + echo $(ECHO_N) "$$grn$(ECHO_C)"; \ + else \ + echo $(ECHO_N) "$$red$(ECHO_C)"; \ + fi; \ + echo "$$msg" | $(am__text_box); \ + echo $(ECHO_N) "$$std$(ECHO_C)"; \ + $$exit + +# Run all the tests. +check-TESTS: + @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list + @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + @list='$(TEST_LOGS)'; \ + list=`for f in $$list; do \ + test .log = $$f || echo $$f; \ + done | tr '\012\015' ' '`; \ + $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$list" + +.log.html: + @list='$(RST2HTML) $$RST2HTML rst2html rst2html.py'; \ + for r2h in $$list; do \ + if ($$r2h --version) >/dev/null 2>&1; then \ + R2H=$$r2h; \ + fi; \ + done; \ + if test -z "$$R2H"; then \ + echo >&2 "cannot find rst2html, cannot create $@"; \ + exit 2; \ + fi; \ + $$R2H $< >$@.tmp + @mv $@.tmp $@ + +# Be sure to run check first, and then to convert the result. +# Beware of concurrent executions. Run "check" not "check-TESTS", as +# check-SCRIPTS and other dependencies are rebuilt by the former only. +# And expect check to fail. +check-html: + @if $(MAKE) $(AM_MAKEFLAGS) check; then \ + rv=0; else rv=$$?; \ + fi; \ + $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_HTML) || exit 4; \ + exit $$rv +recheck recheck-html: + @target=`echo $@ | sed 's,^re,,'`; \ + list='$(TEST_LOGS)'; \ + list=`for f in $$list; do \ + test -f $$f || continue; \ + if read line < $$f; then \ + case $$line in FAIL*|XPASS*) echo $$f;; esac; \ + else echo $$f; fi; \ + done | tr '\012\015' ' '`; \ + $(MAKE) $(AM_MAKEFLAGS) $$target AM_MAKEFLAGS='$(AM_MAKEFLAGS) TEST_LOGS="'"$$list"'"' +bootstrap-test.log: bootstrap-test + @p='bootstrap-test'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post) +bootstrap-test-r.log: bootstrap-test-r + @p='bootstrap-test-r'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post) +bootstrap-test-treehash-chunksize.log: bootstrap-test-treehash-chunksize + @p='bootstrap-test-treehash-chunksize'; $(am__check_pre) $(LOG_COMPILE) "$$tst" $(am__check_post) +.test.log: + @p='$<'; $(am__check_pre) $(TEST_LOG_COMPILE) "$$tst" $(am__check_post) +@am__EXEEXT_TRUE@.test$(EXEEXT).log: +@am__EXEEXT_TRUE@ @p='$<'; $(am__check_pre) $(TEST_LOG_COMPILE) "$$tst" $(am__check_post) +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: check-recursive +all-am: Makefile $(LIBRARIES) $(PROGRAMS) config.h +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS) + -test -z "$(TEST_LOGS_TMP)" || rm -f $(TEST_LOGS_TMP) + -test -z "$(TEST_SUITE_HTML)" || rm -f $(TEST_SUITE_HTML) + -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -rm -f yyscript.c + -rm -f yyscript.h +clean: clean-recursive + +clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-noinstLIBRARIES clean-noinstPROGRAMS mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(DEPDIR) ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-hdr distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: install-data-local + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-exec-local + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -rf $(DEPDIR) ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-binPROGRAMS + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all check-am \ + check-html ctags-recursive install-am install-strip recheck \ + recheck-html tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am am--refresh check check-TESTS check-am check-html \ + clean clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-noinstLIBRARIES clean-noinstPROGRAMS ctags \ + ctags-recursive distclean distclean-compile distclean-generic \ + distclean-hdr distclean-tags dvi dvi-am html html-am info \ + info-am install install-am install-binPROGRAMS install-data \ + install-data-am install-data-local install-dvi install-dvi-am \ + install-exec install-exec-am install-exec-local install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic pdf pdf-am \ + ps ps-am recheck recheck-html tags tags-recursive uninstall \ + uninstall-am uninstall-binPROGRAMS + + +# Use an explicit dependency for the bison generated header file. +expression.$(OBJEXT): yyscript.h +script-sections.$(OBJEXT): yyscript.h +script.$(OBJEXT): yyscript.h + +# We have to build libgold.a before we run the tests. +check: libgold.a + +.PHONY: install-exec-local + +install-exec-local: ld-new$(EXEEXT) + $(mkinstalldirs) $(DESTDIR)$(bindir) $(DESTDIR)$(tooldir)/bin + n=`echo $(installed_linker) | sed '$(transform)'`; \ + $(INSTALL_PROGRAM) ld-new$(EXEEXT) $(DESTDIR)$(bindir)/$${n}$(EXEEXT); \ + if test "$(bindir)" != "$(tooldir)/bin"; then \ + rm -f $(DESTDIR)$(tooldir)/bin/$(installed_linker)$(EXEEXT); \ + ln $(DESTDIR)$(bindir)/$${n}$(EXEEXT) $(DESTDIR)$(tooldir)/bin/$(installed_linker)$(EXEEXT) >/dev/null 2>/dev/null \ + || $(INSTALL_PROGRAM) ld-new$(EXEEXT) $(DESTDIR)$(tooldir)/bin/$(installed_linker)$(EXEEXT); \ + fi; \ + if test "x$(install_as_default)" = "xyes"; then \ + ld=`echo ld | sed '$(transform)'`; \ + rm -f $(DESTDIR)$(bindir)/$${ld}$(EXEEXT); \ + ln $(DESTDIR)$(bindir)/$${n}$(EXEEXT) $(DESTDIR)$(bindir)/$${ld}$(EXEEXT) >/dev/null 2>/dev/null \ + || $(INSTALL_PROGRAM) ld-new$(EXEEXT) $(DESTDIR)$(bindir)/$${ld}$(EXEEXT); \ + if test "$(bindir)" != "$(tooldir)/bin"; then \ + rm -f $(DESTDIR)$(tooldir)/bin/ld$(EXEEXT); \ + ln $(DESTDIR)$(bindir)/$${n}$(EXEEXT) $(DESTDIR)$(tooldir)/bin/ld$(EXEEXT) >/dev/null 2>/dev/null \ + || $(INSTALL_PROGRAM) ld-new$(EXEEXT) $(DESTDIR)$(tooldir)/bin/ld$(EXEEXT); \ + fi; \ + fi + +# We want install to imply install-info as per GNU standards, despite +# the cygnus option. +install-data-local: install-info + +po/POTFILES.in: @MAINT@ Makefile + for f in $(POTFILES); do echo $$f; done | LC_ALL=C sort > tmp \ + && mv tmp $(srcdir)/po/POTFILES.in + +# Bootstrap test support. We use ld-new to build ld1, then use ld1 to +# build ld2. ld1 and ld2 should be identical. ld-new need not be +# identical to ld1, since it was linked with the host linker. + +@GCC_TRUE@@NATIVE_LINKER_TRUE@gcctestdir1/ld: ld-new +@GCC_TRUE@@NATIVE_LINKER_TRUE@ test -d gcctestdir1 || mkdir -p gcctestdir1 +@GCC_TRUE@@NATIVE_LINKER_TRUE@ rm -f gcctestdir1/ld +@GCC_TRUE@@NATIVE_LINKER_TRUE@ (cd gcctestdir1 && $(LN_S) ../ld-new ld) + +@GCC_TRUE@@NATIVE_LINKER_TRUE@gcctestdir2/ld: ld1 +@GCC_TRUE@@NATIVE_LINKER_TRUE@ test -d gcctestdir2 || mkdir -p gcctestdir2 +@GCC_TRUE@@NATIVE_LINKER_TRUE@ rm -f gcctestdir2/ld +@GCC_TRUE@@NATIVE_LINKER_TRUE@ (cd gcctestdir2 && $(LN_S) ../ld1 ld) + +@GCC_TRUE@@NATIVE_LINKER_TRUE@bootstrap-test: ld2 +@GCC_TRUE@@NATIVE_LINKER_TRUE@ rm -f $@ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo "#!/bin/sh" > $@ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo "cmp ld1 ld2" >> $@ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ chmod +x $@ + +@GCC_TRUE@@NATIVE_LINKER_TRUE@libgold-1-r.o: gcctestdir1/ld libgold.a +@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir1/ld -o $@ -r --whole-archive libgold.a + +@GCC_TRUE@@NATIVE_LINKER_TRUE@gcctestdir2-r/ld: ld1-r +@GCC_TRUE@@NATIVE_LINKER_TRUE@ test -d gcctestdir2-r || mkdir -p gcctestdir2-r +@GCC_TRUE@@NATIVE_LINKER_TRUE@ rm -f gcctestdir2-r/ld +@GCC_TRUE@@NATIVE_LINKER_TRUE@ (cd gcctestdir2-r && $(LN_S) ../ld1-r ld) + +@GCC_TRUE@@NATIVE_LINKER_TRUE@libgold-2-r.o: gcctestdir2-r/ld libgold.a +@GCC_TRUE@@NATIVE_LINKER_TRUE@ gcctestdir2-r/ld -o $@ -r --whole-archive libgold.a + +@GCC_TRUE@@NATIVE_LINKER_TRUE@bootstrap-test-r: ld2-r +@GCC_TRUE@@NATIVE_LINKER_TRUE@ rm -f $@ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo "#!/bin/sh" > $@ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo "cmp ld1-r ld2-r" >> $@ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ chmod +x $@ + +@GCC_TRUE@@NATIVE_LINKER_TRUE@gcctestdir3/ld: ld-new +@GCC_TRUE@@NATIVE_LINKER_TRUE@ test -d gcctestdir3 || mkdir -p gcctestdir3 +@GCC_TRUE@@NATIVE_LINKER_TRUE@ rm -f gcctestdir3/ld +@GCC_TRUE@@NATIVE_LINKER_TRUE@ (cd gcctestdir3 && $(LN_S) ../ld-new ld) + +@GCC_TRUE@@NATIVE_LINKER_TRUE@gcctestdir4/ld: ld-new +@GCC_TRUE@@NATIVE_LINKER_TRUE@ test -d gcctestdir4 || mkdir -p gcctestdir4 +@GCC_TRUE@@NATIVE_LINKER_TRUE@ rm -f gcctestdir4/ld +@GCC_TRUE@@NATIVE_LINKER_TRUE@ (cd gcctestdir4 && $(LN_S) ../ld-new ld) + +@GCC_TRUE@@NATIVE_LINKER_TRUE@@THREADS_TRUE@bootstrap-test-treehash: ld1 ld3 +@GCC_TRUE@@NATIVE_LINKER_TRUE@@THREADS_TRUE@ rm -f $@ +@GCC_TRUE@@NATIVE_LINKER_TRUE@@THREADS_TRUE@ echo "#!/bin/sh" > $@ +@GCC_TRUE@@NATIVE_LINKER_TRUE@@THREADS_TRUE@ echo "cmp ld1 ld3" >> $@ +@GCC_TRUE@@NATIVE_LINKER_TRUE@@THREADS_TRUE@ chmod +x $@ + +@GCC_TRUE@@NATIVE_LINKER_TRUE@bootstrap-test-treehash-chunksize: ld1 ld4 +@GCC_TRUE@@NATIVE_LINKER_TRUE@ rm -f $@ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo "#!/bin/sh" > $@ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ echo "cmp ld1 ld4 | grep ." >> $@ +@GCC_TRUE@@NATIVE_LINKER_TRUE@ chmod +x $@ + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/binutils-2.25/gold/NEWS b/binutils-2.25/gold/NEWS new file mode 100644 index 00000000..d73ceeb8 --- /dev/null +++ b/binutils-2.25/gold/NEWS @@ -0,0 +1,11 @@ +* gold added to GNU binutils. + +Copyright (C) 2012 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. + +Local variables: +fill-column: 79 +End: diff --git a/binutils-2.25/gold/README b/binutils-2.25/gold/README new file mode 100644 index 00000000..0fccc134 --- /dev/null +++ b/binutils-2.25/gold/README @@ -0,0 +1,69 @@ +gold is an ELF linker. It is intended to have complete support for +ELF and to run as fast as possible on modern systems. For normal use +it is a drop-in replacement for the older GNU linker. + +gold is part of the GNU binutils. See ../binutils/README for more +general notes, including where to send bug reports. + +gold was originally developed at Google, and was contributed to the +Free Software Foundation in March 2008. At Google it was designed by +Ian Lance Taylor, with major contributions by Cary Coutant, Craig +Silverstein, and Andrew Chatham. + +The existing GNU linker manual is intended to be accurate +documentation for features which gold supports. gold supports most of +the features of the GNU linker for ELF targets. Notable +omissions--features of the GNU linker not currently supported in +gold--are: + * MRI compatible linker scripts + * cross-reference reports (--cref) + * various other minor options + + +Notes on the code +================= + +These are some notes which may be helpful to people working on the +source code of gold itself. + +gold is written in C++. It is a GNU program, and therefore follows +the GNU formatting standards as modified for C++. Source documents in +order of decreasing precedence: + http://www.gnu.org/prep/standards/ + http://gcc.gnu.org/onlinedocs/libstdc++/manual/source_code_style.html + http://www.zembu.com/eng/procs/c++style.html + +The linker is intended to have complete support for cross-compilation, +while still supporting the normal case of native linking as fast as +possible. In order to do this, many classes are actually templates +whose parameter is the ELF file class (e.g., 32 bits or 64 bits). The +C++ code is the same, but we don't pay the execution time cost of +always using 64-bit integers if the target is 32 bits. Many of these +class templates also have an endianness parameter: true for +big-endian, false for little-endian. + +The linker is multi-threaded. The Task class represents a single unit +of work. Task objects are stored on a single Workqueue object. Tasks +communicate via Task_token objects. Task_token objects are only +manipulated while holding the master Workqueue lock. Relatively few +mutexes are used. + + +Build requirements +================== + +The gold source code uses templates heavily. Building it requires a +recent version of g++. g++ 4.0.3 and 4.1.3 are known to work. g++ +3.2, 3.4.3, and 4.1.2 are known to fail. + +The linker script parser uses features which are only in newer +versions of bison. bison 2.3 is known to work. bison 1.26 is known +to fail. If you are building gold from an official binutils release, +the bison output should already be included. + + +Copyright (C) 2012 Free Software Foundation, Inc. + +Copying and distribution of this file, with or without modification, +are permitted in any medium without royalty provided the copyright +notice and this notice are preserved. diff --git a/binutils-2.25/gold/TODO b/binutils-2.25/gold/TODO new file mode 100644 index 00000000..b85df975 --- /dev/null +++ b/binutils-2.25/gold/TODO @@ -0,0 +1,26 @@ +Things that still need to be done: -*- Text -*- + + o - Performance + + All performance could be tuned, but one area that could be looked + at especially is performance with flags, particularly + --detect-odr-violations and --compress-debug-sections. + + o - Threads + + Why is the usertime when we run with threads the same (or almost + the same) as when we run without? Is it because threads spend most + of their time waiting on the same resources? On each other? + Something else? + + o - ODR false positives + + ODR false positives can happen when we optimize, since code in .h + files may be optimized in different ways in different compilation + units. It's possible we could fix this for real by looking at the + full debug info and using DW_TAG_inlined_subroutine in a clever way + to correct for inlining. But that would be very expensive, I + think. The easier solution is to recommend people only do + ODR-detection with -g0. + + o - Better testing diff --git a/binutils-2.25/gold/aclocal.m4 b/binutils-2.25/gold/aclocal.m4 new file mode 100644 index 00000000..83218946 --- /dev/null +++ b/binutils-2.25/gold/aclocal.m4 @@ -0,0 +1,992 @@ +# generated automatically by aclocal 1.11.1 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.64],, +[m4_warning([this file was generated for autoconf 2.64. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically `autoreconf'.])]) + +# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.11' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.11.1], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.11.1])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 9 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 10 + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], UPC, [depcc="$UPC" am_compiler_list=], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + am__universal=false + m4_case([$1], [CC], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac], + [CXX], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac]) + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +#serial 5 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[{ + # Autoconf 2.62 quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 8 + +# AM_CONFIG_HEADER is obsolete. It has been replaced by AC_CONFIG_HEADERS. +AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2008, 2009 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 16 + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.62])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES(OBJC)], + [define([AC_PROG_OBJC], + defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl +]) +_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl +dnl The `parallel-tests' driver may need to know about EXEEXT, so add the +dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro +dnl is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl +]) + +dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001, 2003, 2005, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST(install_sh)]) + +# Add --enable-maintainer-mode option to configure. -*- Autoconf -*- +# From Jim Meyering + +# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_MAINTAINER_MODE([DEFAULT-MODE]) +# ---------------------------------- +# Control maintainer-specific portions of Makefiles. +# Default is to disable them, unless `enable' is passed literally. +# For symmetry, `disable' may be passed as well. Anyway, the user +# can override the default with the --enable/--disable switch. +AC_DEFUN([AM_MAINTAINER_MODE], +[m4_case(m4_default([$1], [disable]), + [enable], [m4_define([am_maintainer_other], [disable])], + [disable], [m4_define([am_maintainer_other], [enable])], + [m4_define([am_maintainer_other], [enable]) + m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])]) +AC_MSG_CHECKING([whether to am_maintainer_other maintainer-specific portions of Makefiles]) + dnl maintainer-mode's default is 'disable' unless 'enable' is passed + AC_ARG_ENABLE([maintainer-mode], +[ --][am_maintainer_other][-maintainer-mode am_maintainer_other make rules and dependencies not useful + (and sometimes confusing) to the casual installer], + [USE_MAINTAINER_MODE=$enableval], + [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes])) + AC_MSG_RESULT([$USE_MAINTAINER_MODE]) + AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes]) + MAINT=$MAINTAINER_MODE_TRUE + AC_SUBST([MAINT])dnl +] +) + +AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from `make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 6 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_MKDIR_P +# --------------- +# Check for `mkdir -p'. +AC_DEFUN([AM_PROG_MKDIR_P], +[AC_PREREQ([2.60])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, +dnl while keeping a definition of mkdir_p for backward compatibility. +dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. +dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of +dnl Makefile.ins that do not define MKDIR_P, so we do our own +dnl adjustment using top_builddir (which is defined more often than +dnl MKDIR_P). +AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl +case $mkdir_p in + [[\\/$]]* | ?:[[\\/]]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 4 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 5 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);; +esac + +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006, 2008 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004, 2005 Free Software Foundation, Inc. +# +# This file is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# serial 2 + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of `v7', `ustar', or `pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. +AM_MISSING_PROG([AMTAR], [tar]) +m4_if([$1], [v7], + [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + +m4_include([../config/depstand.m4]) +m4_include([../config/gettext-sister.m4]) +m4_include([../config/lcmessage.m4]) +m4_include([../config/lead-dot.m4]) +m4_include([../config/nls.m4]) +m4_include([../config/override.m4]) +m4_include([../config/po.m4]) +m4_include([../config/progtest.m4]) +m4_include([../config/zlib.m4]) +m4_include([../bfd/warning.m4]) diff --git a/binutils-2.25/gold/archive.cc b/binutils-2.25/gold/archive.cc new file mode 100644 index 00000000..53d88a23 --- /dev/null +++ b/binutils-2.25/gold/archive.cc @@ -0,0 +1,1313 @@ +// archive.cc -- archive support for gold + +// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2013 +// Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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 +#include +#include +#include +#include "libiberty.h" +#include "filenames.h" + +#include "elfcpp.h" +#include "options.h" +#include "mapfile.h" +#include "fileread.h" +#include "readsyms.h" +#include "symtab.h" +#include "object.h" +#include "layout.h" +#include "archive.h" +#include "plugin.h" +#include "incremental.h" + +namespace gold +{ + +// Library_base methods. + +// Determine whether a definition of SYM_NAME should cause an archive +// library member to be included in the link. Returns SHOULD_INCLUDE_YES +// if the symbol is referenced but not defined, SHOULD_INCLUDE_NO if the +// symbol is already defined, and SHOULD_INCLUDE_UNKNOWN if the symbol is +// neither referenced nor defined. + +Library_base::Should_include +Library_base::should_include_member(Symbol_table* symtab, Layout* layout, + const char* sym_name, Symbol** symp, + std::string* why, char** tmpbufp, + size_t* tmpbuflen) +{ + // In an object file, and therefore in an archive map, an + // '@' in the name separates the symbol name from the + // version name. If there are two '@' characters, this is + // the default version. + char* tmpbuf = *tmpbufp; + const char* ver = strchr(sym_name, '@'); + bool def = false; + if (ver != NULL) + { + size_t symlen = ver - sym_name; + if (symlen + 1 > *tmpbuflen) + { + tmpbuf = static_cast(xrealloc(tmpbuf, symlen + 1)); + *tmpbufp = tmpbuf; + *tmpbuflen = symlen + 1; + } + memcpy(tmpbuf, sym_name, symlen); + tmpbuf[symlen] = '\0'; + sym_name = tmpbuf; + + ++ver; + if (*ver == '@') + { + ++ver; + def = true; + } + } + + Symbol* sym = symtab->lookup(sym_name, ver); + if (def + && ver != NULL + && (sym == NULL + || !sym->is_undefined() + || sym->binding() == elfcpp::STB_WEAK)) + sym = symtab->lookup(sym_name, NULL); + + *symp = sym; + + if (sym == NULL) + { + // Check whether the symbol was named in a -u option. + if (parameters->options().is_undefined(sym_name)) + { + *why = "-u "; + *why += sym_name; + } + else if (parameters->options().is_export_dynamic_symbol(sym_name)) + { + *why = "--export-dynamic-symbol "; + *why += sym_name; + } + else if (layout->script_options()->is_referenced(sym_name)) + { + size_t alc = 100 + strlen(sym_name); + char* buf = new char[alc]; + snprintf(buf, alc, _("script or expression reference to %s"), + sym_name); + *why = buf; + delete[] buf; + } + else if (strcmp(sym_name, parameters->entry()) == 0) + { + *why = "entry symbol "; + *why += sym_name; + } + else + return Library_base::SHOULD_INCLUDE_UNKNOWN; + } + else if (!sym->is_undefined()) + return Library_base::SHOULD_INCLUDE_NO; + // PR 12001: Do not include an archive when the undefined + // symbol has actually been defined on the command line. + else if (layout->script_options()->is_pending_assignment(sym_name)) + return Library_base::SHOULD_INCLUDE_NO; + else if (sym->binding() == elfcpp::STB_WEAK) + return Library_base::SHOULD_INCLUDE_UNKNOWN; + + return Library_base::SHOULD_INCLUDE_YES; +} + +// The header of an entry in the archive. This is all readable text, +// padded with spaces where necessary. If the contents of an archive +// are all text file, the entire archive is readable. + +struct Archive::Archive_header +{ + // The entry name. + char ar_name[16]; + // The file modification time. + char ar_date[12]; + // The user's UID in decimal. + char ar_uid[6]; + // The user's GID in decimal. + char ar_gid[6]; + // The file mode in octal. + char ar_mode[8]; + // The file size in decimal. + char ar_size[10]; + // The final magic code. + char ar_fmag[2]; +}; + +// Class Archive static variables. +unsigned int Archive::total_archives; +unsigned int Archive::total_members; +unsigned int Archive::total_members_loaded; + +// Archive methods. + +const char Archive::armag[sarmag] = +{ + '!', '<', 'a', 'r', 'c', 'h', '>', '\n' +}; + +const char Archive::armagt[sarmag] = +{ + '!', '<', 't', 'h', 'i', 'n', '>', '\n' +}; + +const char Archive::arfmag[2] = { '`', '\n' }; + +Archive::Archive(const std::string& name, Input_file* input_file, + bool is_thin_archive, Dirsearch* dirpath, Task* task) + : Library_base(task), name_(name), input_file_(input_file), armap_(), + armap_names_(), extended_names_(), armap_checked_(), seen_offsets_(), + members_(), is_thin_archive_(is_thin_archive), included_member_(false), + nested_archives_(), dirpath_(dirpath), num_members_(0), + included_all_members_(false) +{ + this->no_export_ = + parameters->options().check_excluded_libs(input_file->found_name()); +} + +// Set up the archive: read the symbol map and the extended name +// table. + +void +Archive::setup() +{ + // We need to ignore empty archives. + if (this->input_file_->file().filesize() == sarmag) + return; + + // The first member of the archive should be the symbol table. + std::string armap_name; + off_t header_size = this->read_header(sarmag, false, &armap_name, NULL); + if (header_size == -1) + return; + + section_size_type armap_size = convert_to_section_size_type(header_size); + off_t off = sarmag; + if (armap_name.empty()) + { + this->read_armap(sarmag + sizeof(Archive_header), armap_size); + off = sarmag + sizeof(Archive_header) + armap_size; + } + else if (!this->input_file_->options().whole_archive()) + gold_error(_("%s: no archive symbol table (run ranlib)"), + this->name().c_str()); + + // See if there is an extended name table. We cache these views + // because it is likely that we will want to read the following + // header in the add_symbols routine. + if ((off & 1) != 0) + ++off; + std::string xname; + header_size = this->read_header(off, true, &xname, NULL); + if (header_size == -1) + return; + + section_size_type extended_size = convert_to_section_size_type(header_size); + if (xname == "/") + { + const unsigned char* p = this->get_view(off + sizeof(Archive_header), + extended_size, false, true); + const char* px = reinterpret_cast(p); + this->extended_names_.assign(px, extended_size); + } + bool preread_syms = (parameters->options().threads() + && parameters->options().preread_archive_symbols()); +#ifndef ENABLE_THREADS + preread_syms = false; +#else + if (parameters->options().has_plugins()) + preread_syms = false; +#endif + if (preread_syms) + this->read_all_symbols(); +} + +// Unlock any nested archives. + +void +Archive::unlock_nested_archives() +{ + for (Nested_archive_table::iterator p = this->nested_archives_.begin(); + p != this->nested_archives_.end(); + ++p) + { + p->second->unlock(this->task_); + } +} + +// Read the archive symbol map. + +void +Archive::read_armap(off_t start, section_size_type size) +{ + // To count the total number of archive members, we'll just count + // the number of times the file offset changes. Since most archives + // group the symbols in the armap by object, this ought to give us + // an accurate count. + off_t last_seen_offset = -1; + + // Read in the entire armap. + const unsigned char* p = this->get_view(start, size, true, false); + + // Numbers in the armap are always big-endian. + const elfcpp::Elf_Word* pword = reinterpret_cast(p); + unsigned int nsyms = elfcpp::Swap<32, true>::readval(pword); + ++pword; + + // Note that the addition is in units of sizeof(elfcpp::Elf_Word). + const char* pnames = reinterpret_cast(pword + nsyms); + section_size_type names_size = + reinterpret_cast(p) + size - pnames; + this->armap_names_.assign(pnames, names_size); + + this->armap_.resize(nsyms); + + section_offset_type name_offset = 0; + for (unsigned int i = 0; i < nsyms; ++i) + { + this->armap_[i].name_offset = name_offset; + this->armap_[i].file_offset = elfcpp::Swap<32, true>::readval(pword); + name_offset += strlen(pnames + name_offset) + 1; + ++pword; + if (this->armap_[i].file_offset != last_seen_offset) + { + last_seen_offset = this->armap_[i].file_offset; + ++this->num_members_; + } + } + + if (static_cast(name_offset) > names_size) + gold_error(_("%s: bad archive symbol table names"), + this->name().c_str()); + + // This array keeps track of which symbols are for archive elements + // which we have already included in the link. + this->armap_checked_.resize(nsyms); +} + +// Read the header of an archive member at OFF. Fail if something +// goes wrong. Return the size of the member. Set *PNAME to the name +// of the member. + +off_t +Archive::read_header(off_t off, bool cache, std::string* pname, + off_t* nested_off) +{ + const unsigned char* p = this->get_view(off, sizeof(Archive_header), true, + cache); + const Archive_header* hdr = reinterpret_cast(p); + return this->interpret_header(hdr, off, pname, nested_off); +} + +// Interpret the header of HDR, the header of the archive member at +// file offset OFF. Return the size of the member, or -1 if something +// has gone wrong. Set *PNAME to the name of the member. + +off_t +Archive::interpret_header(const Archive_header* hdr, off_t off, + std::string* pname, off_t* nested_off) const +{ + if (memcmp(hdr->ar_fmag, arfmag, sizeof arfmag) != 0) + { + gold_error(_("%s: malformed archive header at %zu"), + this->name().c_str(), static_cast(off)); + return -1; + } + + const int size_string_size = sizeof hdr->ar_size; + char size_string[size_string_size + 1]; + memcpy(size_string, hdr->ar_size, size_string_size); + char* ps = size_string + size_string_size; + while (ps[-1] == ' ') + --ps; + *ps = '\0'; + + errno = 0; + char* end; + off_t member_size = strtol(size_string, &end, 10); + if (*end != '\0' + || member_size < 0 + || (member_size == LONG_MAX && errno == ERANGE)) + { + gold_error(_("%s: malformed archive header size at %zu"), + this->name().c_str(), static_cast(off)); + return -1; + } + + if (hdr->ar_name[0] != '/') + { + const char* name_end = strchr(hdr->ar_name, '/'); + if (name_end == NULL + || name_end - hdr->ar_name >= static_cast(sizeof hdr->ar_name)) + { + gold_error(_("%s: malformed archive header name at %zu"), + this->name().c_str(), static_cast(off)); + return -1; + } + pname->assign(hdr->ar_name, name_end - hdr->ar_name); + if (nested_off != NULL) + *nested_off = 0; + } + else if (hdr->ar_name[1] == ' ') + { + // This is the symbol table. + if (!pname->empty()) + pname->clear(); + } + else if (hdr->ar_name[1] == '/') + { + // This is the extended name table. + pname->assign(1, '/'); + } + else + { + errno = 0; + long x = strtol(hdr->ar_name + 1, &end, 10); + long y = 0; + if (*end == ':') + y = strtol(end + 1, &end, 10); + if (*end != ' ' + || x < 0 + || (x == LONG_MAX && errno == ERANGE) + || static_cast(x) >= this->extended_names_.size()) + { + gold_error(_("%s: bad extended name index at %zu"), + this->name().c_str(), static_cast(off)); + return -1; + } + + const char* name = this->extended_names_.data() + x; + const char* name_end = strchr(name, '\n'); + if (static_cast(name_end - name) > this->extended_names_.size() + || name_end[-1] != '/') + { + gold_error(_("%s: bad extended name entry at header %zu"), + this->name().c_str(), static_cast(off)); + return -1; + } + pname->assign(name, name_end - 1 - name); + if (nested_off != NULL) + *nested_off = y; + } + + return member_size; +} + +// An archive member iterator. + +class Archive::const_iterator +{ + public: + // The header of an archive member. This is what this iterator + // points to. + struct Header + { + // The name of the member. + std::string name; + // The file offset of the member. + off_t off; + // The file offset of a nested archive member. + off_t nested_off; + // The size of the member. + off_t size; + }; + + const_iterator(Archive* archive, off_t off) + : archive_(archive), off_(off) + { this->read_next_header(); } + + const Header& + operator*() const + { return this->header_; } + + const Header* + operator->() const + { return &this->header_; } + + const_iterator& + operator++() + { + if (this->off_ == this->archive_->file().filesize()) + return *this; + this->off_ += sizeof(Archive_header); + if (!this->archive_->is_thin_archive()) + this->off_ += this->header_.size; + if ((this->off_ & 1) != 0) + ++this->off_; + this->read_next_header(); + return *this; + } + + const_iterator + operator++(int) + { + const_iterator ret = *this; + ++*this; + return ret; + } + + bool + operator==(const const_iterator p) const + { return this->off_ == p->off; } + + bool + operator!=(const const_iterator p) const + { return this->off_ != p->off; } + + private: + void + read_next_header(); + + // The underlying archive. + Archive* archive_; + // The current offset in the file. + off_t off_; + // The current archive header. + Header header_; +}; + +// Read the next archive header. + +void +Archive::const_iterator::read_next_header() +{ + off_t filesize = this->archive_->file().filesize(); + while (true) + { + if (filesize - this->off_ < static_cast(sizeof(Archive_header))) + { + if (filesize != this->off_) + { + gold_error(_("%s: short archive header at %zu"), + this->archive_->filename().c_str(), + static_cast(this->off_)); + this->off_ = filesize; + } + this->header_.off = filesize; + return; + } + + unsigned char buf[sizeof(Archive_header)]; + this->archive_->file().read(this->off_, sizeof(Archive_header), buf); + + const Archive_header* hdr = reinterpret_cast(buf); + off_t size = this->archive_->interpret_header(hdr, this->off_, + &this->header_.name, + &this->header_.nested_off); + if (size == -1) + { + this->header_.off = filesize; + return; + } + + this->header_.size = size; + this->header_.off = this->off_; + + // Skip special members. + if (!this->header_.name.empty() && this->header_.name != "/") + return; + + this->off_ += sizeof(Archive_header) + this->header_.size; + if ((this->off_ & 1) != 0) + ++this->off_; + } +} + +// Initial iterator. + +Archive::const_iterator +Archive::begin() +{ + return Archive::const_iterator(this, sarmag); +} + +// Final iterator. + +Archive::const_iterator +Archive::end() +{ + return Archive::const_iterator(this, this->input_file_->file().filesize()); +} + +// Get the file and offset for an archive member, which may be an +// external member of a thin archive. Set *INPUT_FILE to the +// file containing the actual member, *MEMOFF to the offset +// within that file (0 if not a nested archive), and *MEMBER_NAME +// to the name of the archive member. Return TRUE on success. + +bool +Archive::get_file_and_offset(off_t off, Input_file** input_file, off_t* memoff, + off_t* memsize, std::string* member_name) +{ + off_t nested_off; + + *memsize = this->read_header(off, false, member_name, &nested_off); + if (*memsize == -1) + return false; + + *input_file = this->input_file_; + *memoff = off + static_cast(sizeof(Archive_header)); + + if (!this->is_thin_archive_) + return true; + + // Adjust a relative pathname so that it is relative + // to the directory containing the archive. + if (!IS_ABSOLUTE_PATH(member_name->c_str())) + { + const char* arch_path = this->filename().c_str(); + const char* basename = lbasename(arch_path); + if (basename > arch_path) + member_name->replace(0, 0, + this->filename().substr(0, basename - arch_path)); + } + + if (nested_off > 0) + { + // This is a member of a nested archive. Open the containing + // archive if we don't already have it open, then do a recursive + // call to include the member from that archive. + Archive* arch; + Nested_archive_table::const_iterator p = + this->nested_archives_.find(*member_name); + if (p != this->nested_archives_.end()) + arch = p->second; + else + { + Input_file_argument* input_file_arg = + new Input_file_argument(member_name->c_str(), + Input_file_argument::INPUT_FILE_TYPE_FILE, + "", false, parameters->options()); + *input_file = new Input_file(input_file_arg); + int dummy = 0; + if (!(*input_file)->open(*this->dirpath_, this->task_, &dummy)) + return false; + arch = new Archive(*member_name, *input_file, false, this->dirpath_, + this->task_); + arch->setup(); + std::pair ins = + this->nested_archives_.insert(std::make_pair(*member_name, arch)); + gold_assert(ins.second); + } + return arch->get_file_and_offset(nested_off, input_file, memoff, + memsize, member_name); + } + + // This is an external member of a thin archive. Open the + // file as a regular relocatable object file. + Input_file_argument* input_file_arg = + new Input_file_argument(member_name->c_str(), + Input_file_argument::INPUT_FILE_TYPE_FILE, + "", false, this->input_file_->options()); + *input_file = new Input_file(input_file_arg); + int dummy = 0; + if (!(*input_file)->open(*this->dirpath_, this->task_, &dummy)) + return false; + + *memoff = 0; + *memsize = (*input_file)->file().filesize(); + return true; +} + +// Return an ELF object for the member at offset OFF. If +// PUNCONFIGURED is not NULL, then if the ELF object has an +// unsupported target type, set *PUNCONFIGURED to true and return +// NULL. + +Object* +Archive::get_elf_object_for_member(off_t off, bool* punconfigured) +{ + if (punconfigured != NULL) + *punconfigured = false; + + Input_file* input_file; + off_t memoff; + off_t memsize; + std::string member_name; + if (!this->get_file_and_offset(off, &input_file, &memoff, &memsize, + &member_name)) + return NULL; + + const unsigned char* ehdr; + int read_size; + Object *obj = NULL; + bool is_elf_obj = false; + + if (is_elf_object(input_file, memoff, &ehdr, &read_size)) + { + obj = make_elf_object((std::string(this->input_file_->filename()) + + "(" + member_name + ")"), + input_file, memoff, ehdr, read_size, + punconfigured); + is_elf_obj = true; + } + + if (parameters->options().has_plugins()) + { + Object* plugin_obj + = parameters->options().plugins()->claim_file(input_file, + memoff, + memsize, + obj); + if (plugin_obj != NULL) + { + // The input file was claimed by a plugin, and its symbols + // have been provided by the plugin. + // Delete its elf object. + if (obj != NULL) + delete obj; + return plugin_obj; + } + } + + if (!is_elf_obj) + { + gold_error(_("%s: member at %zu is not an ELF object"), + this->name().c_str(), static_cast(off)); + return NULL; + } + + if (obj == NULL) + return NULL; + obj->set_no_export(this->no_export()); + return obj; +} + +// Read the symbols from all the archive members in the link. + +void +Archive::read_all_symbols() +{ + for (Archive::const_iterator p = this->begin(); + p != this->end(); + ++p) + this->read_symbols(p->off); +} + +// Read the symbols from an archive member in the link. OFF is the file +// offset of the member header. + +void +Archive::read_symbols(off_t off) +{ + Object* obj = this->get_elf_object_for_member(off, NULL); + if (obj == NULL) + return; + + Read_symbols_data* sd = new Read_symbols_data; + obj->read_symbols(sd); + Archive_member member(obj, sd); + this->members_[off] = member; +} + +// Select members from the archive and add them to the link. We walk +// through the elements in the archive map, and look each one up in +// the symbol table. If it exists as a strong undefined symbol, we +// pull in the corresponding element. We have to do this in a loop, +// since pulling in one element may create new undefined symbols which +// may be satisfied by other objects in the archive. Return true in +// the normal case, false if the first member we tried to add from +// this archive had an incompatible target. + +bool +Archive::add_symbols(Symbol_table* symtab, Layout* layout, + Input_objects* input_objects, Mapfile* mapfile) +{ + ++Archive::total_archives; + + if (this->input_file_->options().whole_archive()) + return this->include_all_members(symtab, layout, input_objects, + mapfile); + + Archive::total_members += this->num_members_; + + input_objects->archive_start(this); + + const size_t armap_size = this->armap_.size(); + + // This is a quick optimization, since we usually see many symbols + // in a row with the same offset. last_seen_offset holds the last + // offset we saw that was present in the seen_offsets_ set. + off_t last_seen_offset = -1; + + // Track which symbols in the symbol table we've already found to be + // defined. + + char* tmpbuf = NULL; + size_t tmpbuflen = 0; + bool added_new_object; + do + { + added_new_object = false; + for (size_t i = 0; i < armap_size; ++i) + { + if (this->armap_checked_[i]) + continue; + if (this->armap_[i].file_offset == last_seen_offset) + { + this->armap_checked_[i] = true; + continue; + } + if (this->seen_offsets_.find(this->armap_[i].file_offset) + != this->seen_offsets_.end()) + { + this->armap_checked_[i] = true; + last_seen_offset = this->armap_[i].file_offset; + continue; + } + + const char* sym_name = (this->armap_names_.data() + + this->armap_[i].name_offset); + + Symbol* sym; + std::string why; + Archive::Should_include t = + Archive::should_include_member(symtab, layout, sym_name, &sym, + &why, &tmpbuf, &tmpbuflen); + + if (t == Archive::SHOULD_INCLUDE_NO + || t == Archive::SHOULD_INCLUDE_YES) + this->armap_checked_[i] = true; + + if (t != Archive::SHOULD_INCLUDE_YES) + continue; + + // We want to include this object in the link. + last_seen_offset = this->armap_[i].file_offset; + this->seen_offsets_.insert(last_seen_offset); + + if (!this->include_member(symtab, layout, input_objects, + last_seen_offset, mapfile, sym, + why.c_str())) + { + if (tmpbuf != NULL) + free(tmpbuf); + return false; + } + + added_new_object = true; + } + } + while (added_new_object); + + if (tmpbuf != NULL) + free(tmpbuf); + + input_objects->archive_stop(this); + + return true; +} + +// Return whether the archive includes a member which defines the +// symbol SYM. + +bool +Archive::defines_symbol(Symbol* sym) const +{ + const char* symname = sym->name(); + size_t symname_len = strlen(symname); + size_t armap_size = this->armap_.size(); + for (size_t i = 0; i < armap_size; ++i) + { + if (this->armap_checked_[i]) + continue; + const char* archive_symname = (this->armap_names_.data() + + this->armap_[i].name_offset); + if (strncmp(archive_symname, symname, symname_len) != 0) + continue; + char c = archive_symname[symname_len]; + if (c == '\0' && sym->version() == NULL) + return true; + if (c == '@') + { + const char* ver = archive_symname + symname_len + 1; + if (*ver == '@') + { + if (sym->version() == NULL) + return true; + ++ver; + } + if (sym->version() != NULL && strcmp(sym->version(), ver) == 0) + return true; + } + } + return false; +} + +// Include all the archive members in the link. This is for --whole-archive. + +bool +Archive::include_all_members(Symbol_table* symtab, Layout* layout, + Input_objects* input_objects, Mapfile* mapfile) +{ + // Don't include the same archive twice. This can happen if + // --whole-archive is nested inside --start-group (PR gold/12163). + if (this->included_all_members_) + return true; + + this->included_all_members_ = true; + + input_objects->archive_start(this); + + if (this->members_.size() > 0) + { + std::map::const_iterator p; + for (p = this->members_.begin(); + p != this->members_.end(); + ++p) + { + if (!this->include_member(symtab, layout, input_objects, p->first, + mapfile, NULL, "--whole-archive")) + return false; + ++Archive::total_members; + } + } + else + { + for (Archive::const_iterator p = this->begin(); + p != this->end(); + ++p) + { + if (!this->include_member(symtab, layout, input_objects, p->off, + mapfile, NULL, "--whole-archive")) + return false; + ++Archive::total_members; + } + } + + input_objects->archive_stop(this); + + return true; +} + +// Return the number of members in the archive. This is only used for +// reports. + +size_t +Archive::count_members() +{ + size_t ret = 0; + for (Archive::const_iterator p = this->begin(); + p != this->end(); + ++p) + ++ret; + return ret; +} + +// Include an archive member in the link. OFF is the file offset of +// the member header. WHY is the reason we are including this member. +// Return true if we added the member or if we had an error, return +// false if this was the first member we tried to add from this +// archive and it had an incompatible format. + +bool +Archive::include_member(Symbol_table* symtab, Layout* layout, + Input_objects* input_objects, off_t off, + Mapfile* mapfile, Symbol* sym, const char* why) +{ + ++Archive::total_members_loaded; + + std::map::const_iterator p = this->members_.find(off); + if (p != this->members_.end()) + { + Object* obj = p->second.obj_; + + Read_symbols_data* sd = p->second.sd_; + if (mapfile != NULL) + mapfile->report_include_archive_member(obj->name(), sym, why); + if (input_objects->add_object(obj)) + { + obj->layout(symtab, layout, sd); + obj->add_symbols(symtab, sd, layout); + this->included_member_ = true; + } + delete sd; + return true; + } + + // If this is the first object we are including from this archive, + // and we searched for this archive, most likely because it was + // found via a -l option, then if the target is incompatible we want + // to move on to the next archive found in the search path. + bool unconfigured = false; + bool* punconfigured = NULL; + if (!this->included_member_ && this->searched_for()) + punconfigured = &unconfigured; + + Object* obj = this->get_elf_object_for_member(off, punconfigured); + if (obj == NULL) + { + // Return false to search for another archive, true if we found + // an error. + return unconfigured ? false : true; + } + + if (mapfile != NULL) + mapfile->report_include_archive_member(obj->name(), sym, why); + + Pluginobj* pluginobj = obj->pluginobj(); + if (pluginobj != NULL) + { + pluginobj->add_symbols(symtab, NULL, layout); + this->included_member_ = true; + return true; + } + + if (!input_objects->add_object(obj)) + { + // If this is an external member of a thin archive, unlock the + // file. + if (obj->offset() == 0) + obj->unlock(this->task_); + delete obj; + } + else + { + { + if (layout->incremental_inputs() != NULL) + layout->incremental_inputs()->report_object(obj, 0, this, NULL); + Read_symbols_data sd; + obj->read_symbols(&sd); + obj->layout(symtab, layout, &sd); + obj->add_symbols(symtab, &sd, layout); + } + + // If this is an external member of a thin archive, unlock the file + // for the next task. + if (obj->offset() == 0) + obj->unlock(this->task_); + + this->included_member_ = true; + } + + return true; +} + +// Iterate over all unused symbols, and call the visitor class V for each. + +void +Archive::do_for_all_unused_symbols(Symbol_visitor_base* v) const +{ + for (std::vector::const_iterator p = this->armap_.begin(); + p != this->armap_.end(); + ++p) + { + if (this->seen_offsets_.find(p->file_offset) + == this->seen_offsets_.end()) + v->visit(this->armap_names_.data() + p->name_offset); + } +} + +// Print statistical information to stderr. This is used for --stats. + +void +Archive::print_stats() +{ + fprintf(stderr, _("%s: archive libraries: %u\n"), + program_name, Archive::total_archives); + fprintf(stderr, _("%s: total archive members: %u\n"), + program_name, Archive::total_members); + fprintf(stderr, _("%s: loaded archive members: %u\n"), + program_name, Archive::total_members_loaded); +} + +// Add_archive_symbols methods. + +Add_archive_symbols::~Add_archive_symbols() +{ + if (this->this_blocker_ != NULL) + delete this->this_blocker_; + // next_blocker_ is deleted by the task associated with the next + // input file. +} + +// Return whether we can add the archive symbols. We are blocked by +// this_blocker_. We block next_blocker_. We also lock the file. + +Task_token* +Add_archive_symbols::is_runnable() +{ + if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked()) + return this->this_blocker_; + return NULL; +} + +void +Add_archive_symbols::locks(Task_locker* tl) +{ + tl->add(this, this->next_blocker_); + tl->add(this, this->archive_->token()); +} + +void +Add_archive_symbols::run(Workqueue* workqueue) +{ + // For an incremental link, begin recording layout information. + Incremental_inputs* incremental_inputs = this->layout_->incremental_inputs(); + if (incremental_inputs != NULL) + { + unsigned int arg_serial = this->input_argument_->file().arg_serial(); + Script_info* script_info = this->input_argument_->script_info(); + incremental_inputs->report_archive_begin(this->archive_, arg_serial, + script_info); + } + + bool added = this->archive_->add_symbols(this->symtab_, this->layout_, + this->input_objects_, + this->mapfile_); + this->archive_->unlock_nested_archives(); + + this->archive_->release(); + this->archive_->clear_uncached_views(); + + if (!added) + { + // This archive holds object files which are incompatible with + // our output file. + Read_symbols::incompatible_warning(this->input_argument_, + this->archive_->input_file()); + Read_symbols::requeue(workqueue, this->input_objects_, this->symtab_, + this->layout_, this->dirpath_, this->dirindex_, + this->mapfile_, this->input_argument_, + this->input_group_, this->next_blocker_); + delete this->archive_; + return; + } + + if (this->input_group_ != NULL) + this->input_group_->add_archive(this->archive_); + else + { + // For an incremental link, finish recording the layout information. + if (incremental_inputs != NULL) + incremental_inputs->report_archive_end(this->archive_); + + if (!parameters->options().has_plugins() + || this->archive_->input_file()->options().whole_archive()) + { + // We no longer need to know about this archive. + delete this->archive_; + } + else + { + // The plugin interface may want to rescan this archive. + parameters->options().plugins()->save_archive(this->archive_); + } + + this->archive_ = NULL; + } +} + +// Class Lib_group static variables. +unsigned int Lib_group::total_lib_groups; +unsigned int Lib_group::total_members; +unsigned int Lib_group::total_members_loaded; + +Lib_group::Lib_group(const Input_file_lib* lib, Task* task) + : Library_base(task), members_() +{ + this->members_.resize(lib->size()); +} + +const std::string& +Lib_group::do_filename() const +{ + std::string *filename = new std::string("/group/"); + return *filename; +} + +// Select members from the lib group and add them to the link. We walk +// through the members, and check if each one up should be included. +// If the object says it should be included, we do so. We have to do +// this in a loop, since including one member may create new undefined +// symbols which may be satisfied by other members. + +void +Lib_group::add_symbols(Symbol_table* symtab, Layout* layout, + Input_objects* input_objects) +{ + ++Lib_group::total_lib_groups; + + Lib_group::total_members += this->members_.size(); + + bool added_new_object; + do + { + added_new_object = false; + unsigned int i = 0; + while (i < this->members_.size()) + { + const Archive_member& member = this->members_[i]; + Object* obj = member.obj_; + std::string why; + + // Skip files with no symbols. Plugin objects have + // member.sd_ == NULL. + if (obj != NULL + && (member.sd_ == NULL || member.sd_->symbol_names != NULL)) + { + Archive::Should_include t = obj->should_include_member(symtab, + layout, + member.sd_, + &why); + + if (t != Archive::SHOULD_INCLUDE_YES) + { + ++i; + continue; + } + + this->include_member(symtab, layout, input_objects, member); + + added_new_object = true; + } + else + { + if (member.sd_ != NULL) + { + // The file must be locked in order to destroy the views + // associated with it. + gold_assert(obj != NULL); + obj->lock(this->task_); + delete member.sd_; + obj->unlock(this->task_); + } + } + + this->members_[i] = this->members_.back(); + this->members_.pop_back(); + } + } + while (added_new_object); +} + +// Include a lib group member in the link. + +void +Lib_group::include_member(Symbol_table* symtab, Layout* layout, + Input_objects* input_objects, + const Archive_member& member) +{ + ++Lib_group::total_members_loaded; + + Object* obj = member.obj_; + gold_assert(obj != NULL); + + Pluginobj* pluginobj = obj->pluginobj(); + if (pluginobj != NULL) + { + pluginobj->add_symbols(symtab, NULL, layout); + return; + } + + Read_symbols_data* sd = member.sd_; + gold_assert(sd != NULL); + obj->lock(this->task_); + if (input_objects->add_object(obj)) + { + if (layout->incremental_inputs() != NULL) + layout->incremental_inputs()->report_object(obj, member.arg_serial_, + this, NULL); + obj->layout(symtab, layout, sd); + obj->add_symbols(symtab, sd, layout); + } + delete sd; + // Unlock the file for the next task. + obj->unlock(this->task_); +} + +// Iterate over all unused symbols, and call the visitor class V for each. + +void +Lib_group::do_for_all_unused_symbols(Symbol_visitor_base* v) const +{ + // Files are removed from the members list when used, so all the + // files remaining on the list are unused. + for (std::vector::const_iterator p = this->members_.begin(); + p != this->members_.end(); + ++p) + { + Object* obj = p->obj_; + obj->for_all_global_symbols(p->sd_, v); + } +} + +// Print statistical information to stderr. This is used for --stats. + +void +Lib_group::print_stats() +{ + fprintf(stderr, _("%s: lib groups: %u\n"), + program_name, Lib_group::total_lib_groups); + fprintf(stderr, _("%s: total lib groups members: %u\n"), + program_name, Lib_group::total_members); + fprintf(stderr, _("%s: loaded lib groups members: %u\n"), + program_name, Lib_group::total_members_loaded); +} + +Task_token* +Add_lib_group_symbols::is_runnable() +{ + if (this->readsyms_blocker_ != NULL && this->readsyms_blocker_->is_blocked()) + return this->readsyms_blocker_; + if (this->this_blocker_ != NULL && this->this_blocker_->is_blocked()) + return this->this_blocker_; + return NULL; +} + +void +Add_lib_group_symbols::locks(Task_locker* tl) +{ + tl->add(this, this->next_blocker_); +} + +void +Add_lib_group_symbols::run(Workqueue*) +{ + // For an incremental link, begin recording layout information. + Incremental_inputs* incremental_inputs = this->layout_->incremental_inputs(); + if (incremental_inputs != NULL) + incremental_inputs->report_archive_begin(this->lib_, 0, NULL); + + this->lib_->add_symbols(this->symtab_, this->layout_, this->input_objects_); + + if (incremental_inputs != NULL) + incremental_inputs->report_archive_end(this->lib_); +} + +Add_lib_group_symbols::~Add_lib_group_symbols() +{ + if (this->this_blocker_ != NULL) + delete this->this_blocker_; + // next_blocker_ is deleted by the task associated with the next + // input file. +} + +} // End namespace gold. diff --git a/binutils-2.25/gold/archive.h b/binutils-2.25/gold/archive.h new file mode 100644 index 00000000..3d75de62 --- /dev/null +++ b/binutils-2.25/gold/archive.h @@ -0,0 +1,571 @@ +// archive.h -- archive support for gold -*- C++ -*- + +// Copyright 2006, 2007, 2008, 2010, 2011, 2013 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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. + +#ifndef GOLD_ARCHIVE_H +#define GOLD_ARCHIVE_H + +#include +#include + +#include "fileread.h" +#include "workqueue.h" + +namespace gold +{ + +class Task; +class Input_argument; +class Input_file; +class Input_objects; +class Input_group; +class Layout; +class Symbol_table; +class Object; +struct Read_symbols_data; +class Input_file_lib; +class Incremental_archive_entry; + +// An entry in the archive map of offsets to members. +struct Archive_member +{ + Archive_member() + : obj_(NULL), sd_(NULL), arg_serial_(0) + { } + Archive_member(Object* obj, Read_symbols_data* sd) + : obj_(obj), sd_(sd), arg_serial_(0) + { } + // The object file. + Object* obj_; + // The data to pass from read_symbols() to add_symbols(). + Read_symbols_data* sd_; + // The serial number of the file in the argument list. + unsigned int arg_serial_; +}; + +// This class serves as a base class for Archive and Lib_group objects. + +class Library_base +{ + public: + Library_base(Task* task) + : task_(task), incremental_info_(NULL) + { } + + virtual + ~Library_base() + { } + + // The file name. + const std::string& + filename() const + { return this->do_filename(); } + + // The modification time of the archive file. + Timespec + get_mtime() + { return this->do_get_mtime(); } + + // When we see a symbol in an archive we might decide to include the member, + // not include the member or be undecided. This enum represents these + // possibilities. + + enum Should_include + { + SHOULD_INCLUDE_NO, + SHOULD_INCLUDE_YES, + SHOULD_INCLUDE_UNKNOWN + }; + + static Should_include + should_include_member(Symbol_table* symtab, Layout*, const char* sym_name, + Symbol** symp, std::string* why, char** tmpbufp, + size_t* tmpbuflen); + + // Store a pointer to the incremental link info for the library. + void + set_incremental_info(Incremental_archive_entry* info) + { this->incremental_info_ = info; } + + // Return the pointer to the incremental link info for the library. + Incremental_archive_entry* + incremental_info() const + { return this->incremental_info_; } + + // Abstract base class for processing unused symbols. + class Symbol_visitor_base + { + public: + Symbol_visitor_base() + { } + + virtual + ~Symbol_visitor_base() + { } + + // This function will be called for each unused global + // symbol in a library, with a pointer to the symbol name. + virtual void + visit(const char* /* name */) = 0; + }; + + // Iterator for unused global symbols in the library. + // Calls v->visit() for each global symbol defined + // in each unused library member, passing a pointer to + // the symbol name. + void + for_all_unused_symbols(Symbol_visitor_base* v) const + { this->do_for_all_unused_symbols(v); } + + protected: + // The task reading this archive. + Task *task_; + + private: + // The file name. + virtual const std::string& + do_filename() const = 0; + + // Return the modification time of the archive file. + virtual Timespec + do_get_mtime() = 0; + + // Iterator for unused global symbols in the library. + virtual void + do_for_all_unused_symbols(Symbol_visitor_base* v) const = 0; + + // The incremental link information for this archive. + Incremental_archive_entry* incremental_info_; +}; + +// This class represents an archive--generally a libNAME.a file. +// Archives have a symbol table and a list of objects. + +class Archive : public Library_base +{ + public: + Archive(const std::string& name, Input_file* input_file, + bool is_thin_archive, Dirsearch* dirpath, Task* task); + + // The length of the magic string at the start of an archive. + static const int sarmag = 8; + + // The magic string at the start of an archive. + static const char armag[sarmag]; + static const char armagt[sarmag]; + + // The string expected at the end of an archive member header. + static const char arfmag[2]; + + // The name of the object. This is the name used on the command + // line; e.g., if "-lgcc" is on the command line, this will be + // "gcc". + const std::string& + name() const + { return this->name_; } + + // The input file. + const Input_file* + input_file() const + { return this->input_file_; } + + // Set up the archive: read the symbol map. + void + setup(); + + // Get a reference to the underlying file. + File_read& + file() + { return this->input_file_->file(); } + + const File_read& + file() const + { return this->input_file_->file(); } + + // Lock the underlying file. + void + lock(const Task* t) + { this->input_file_->file().lock(t); } + + // Unlock the underlying file. + void + unlock(const Task* t) + { this->input_file_->file().unlock(t); } + + // Return whether the underlying file is locked. + bool + is_locked() const + { return this->input_file_->file().is_locked(); } + + // Return the token, so that the task can be queued. + Task_token* + token() + { return this->input_file_->file().token(); } + + // Release the underlying file. + void + release() + { this->input_file_->file().release(); } + + // Clear uncached views in the underlying file. + void + clear_uncached_views() + { this->input_file_->file().clear_uncached_views(); } + + // Whether this is a thin archive. + bool + is_thin_archive() const + { return this->is_thin_archive_; } + + // Unlock any nested archives. + void + unlock_nested_archives(); + + // Select members from the archive as needed and add them to the + // link. + bool + add_symbols(Symbol_table*, Layout*, Input_objects*, Mapfile*); + + // Return whether the archive defines the symbol. + bool + defines_symbol(Symbol*) const; + + // Dump statistical information to stderr. + static void + print_stats(); + + // Return the number of members in the archive. + size_t + count_members(); + + // Return the no-export flag. + bool + no_export() + { return this->no_export_; } + + private: + Archive(const Archive&); + Archive& operator=(const Archive&); + + // The file name. + const std::string& + do_filename() const + { return this->input_file_->filename(); } + + // The modification time of the archive file. + Timespec + do_get_mtime() + { return this->file().get_mtime(); } + + struct Archive_header; + + // Total number of archives seen. + static unsigned int total_archives; + // Total number of archive members seen. + static unsigned int total_members; + // Number of archive members loaded. + static unsigned int total_members_loaded; + + // Get a view into the underlying file. + const unsigned char* + get_view(off_t start, section_size_type size, bool aligned, bool cache) + { return this->input_file_->file().get_view(0, start, size, aligned, cache); } + + // Read the archive symbol map. + void + read_armap(off_t start, section_size_type size); + + // Read an archive member header at OFF. CACHE is whether to cache + // the file view. Return the size of the member, and set *PNAME to + // the name. + off_t + read_header(off_t off, bool cache, std::string* pname, off_t* nested_off); + + // Interpret an archive header HDR at OFF. Return the size of the + // member, and set *PNAME to the name. + off_t + interpret_header(const Archive_header* hdr, off_t off, std::string* pname, + off_t* nested_off) const; + + // Get the file and offset for an archive member, which may be an + // external member of a thin archive. Set *INPUT_FILE to the + // file containing the actual member, *MEMOFF to the offset + // within that file (0 if not a nested archive), and *MEMBER_NAME + // to the name of the archive member. Return TRUE on success. + bool + get_file_and_offset(off_t off, Input_file** input_file, off_t* memoff, + off_t* memsize, std::string* member_name); + + // Return an ELF object for the member at offset OFF. + Object* + get_elf_object_for_member(off_t off, bool*); + + // Read the symbols from all the archive members in the link. + void + read_all_symbols(); + + // Read the symbols from an archive member in the link. OFF is the file + // offset of the member header. + void + read_symbols(off_t off); + + // Include all the archive members in the link. + bool + include_all_members(Symbol_table*, Layout*, Input_objects*, Mapfile*); + + // Include an archive member in the link. + bool + include_member(Symbol_table*, Layout*, Input_objects*, off_t off, + Mapfile*, Symbol*, const char* why); + + // Return whether we found this archive by searching a directory. + bool + searched_for() const + { return this->input_file_->will_search_for(); } + + // Iterate over archive members. + class const_iterator; + + const_iterator + begin(); + + const_iterator + end(); + + friend class const_iterator; + + // Iterator for unused global symbols in the library. + void + do_for_all_unused_symbols(Symbol_visitor_base* v) const; + + // An entry in the archive map of symbols to object files. + struct Armap_entry + { + // The offset to the symbol name in armap_names_. + off_t name_offset; + // The file offset to the object in the archive. + off_t file_offset; + }; + + // A simple hash code for off_t values. + class Seen_hash + { + public: + size_t operator()(off_t val) const + { return static_cast(val); } + }; + + // For keeping track of open nested archives in a thin archive file. + typedef Unordered_map Nested_archive_table; + + // Name of object as printed to user. + std::string name_; + // For reading the file. + Input_file* input_file_; + // The archive map. + std::vector armap_; + // The names in the archive map. + std::string armap_names_; + // The extended name table. + std::string extended_names_; + // Track which symbols in the archive map are for elements which are + // defined or which have already been included in the link. + std::vector armap_checked_; + // Track which elements have been included by offset. + Unordered_set seen_offsets_; + // Table of objects whose symbols have been pre-read. + std::map members_; + // True if this is a thin archive. + const bool is_thin_archive_; + // True if we have included at least one object from this archive. + bool included_member_; + // Table of nested archives, indexed by filename. + Nested_archive_table nested_archives_; + // The directory search path. + Dirsearch* dirpath_; + // Number of members in this archive; + unsigned int num_members_; + // True if we exclude this library archive from automatic export. + bool no_export_; + // True if this library has been included as a --whole-archive. + bool included_all_members_; +}; + +// This class is used to read an archive and pick out the desired +// elements and add them to the link. + +class Add_archive_symbols : public Task +{ + public: + Add_archive_symbols(Symbol_table* symtab, Layout* layout, + Input_objects* input_objects, Dirsearch* dirpath, + int dirindex, Mapfile* mapfile, + const Input_argument* input_argument, + Archive* archive, Input_group* input_group, + Task_token* this_blocker, + Task_token* next_blocker) + : symtab_(symtab), layout_(layout), input_objects_(input_objects), + dirpath_(dirpath), dirindex_(dirindex), mapfile_(mapfile), + input_argument_(input_argument), archive_(archive), + input_group_(input_group), this_blocker_(this_blocker), + next_blocker_(next_blocker) + { } + + ~Add_archive_symbols(); + + // The standard Task methods. + + Task_token* + is_runnable(); + + void + locks(Task_locker*); + + void + run(Workqueue*); + + std::string + get_name() const + { + if (this->archive_ == NULL) + return "Add_archive_symbols"; + return "Add_archive_symbols " + this->archive_->file().filename(); + } + + private: + Symbol_table* symtab_; + Layout* layout_; + Input_objects* input_objects_; + Dirsearch* dirpath_; + int dirindex_; + Mapfile* mapfile_; + const Input_argument* input_argument_; + Archive* archive_; + Input_group* input_group_; + Task_token* this_blocker_; + Task_token* next_blocker_; +}; + +// This class represents the files surrounded by a --start-lib ... --end-lib. + +class Lib_group : public Library_base +{ + public: + Lib_group(const Input_file_lib* lib, Task* task); + + // Select members from the lib group as needed and add them to the link. + void + add_symbols(Symbol_table*, Layout*, Input_objects*); + + // Include a member of the lib group in the link. + void + include_member(Symbol_table*, Layout*, Input_objects*, const Archive_member&); + + Archive_member* + get_member(int i) + { + return &this->members_[i]; + } + + // Total number of archives seen. + static unsigned int total_lib_groups; + // Total number of archive members seen. + static unsigned int total_members; + // Number of archive members loaded. + static unsigned int total_members_loaded; + + // Dump statistical information to stderr. + static void + print_stats(); + + private: + // The file name. + const std::string& + do_filename() const; + + // A Lib_group does not have a modification time, since there is no + // real library file. + Timespec + do_get_mtime() + { return Timespec(0, 0); } + + // Iterator for unused global symbols in the library. + void + do_for_all_unused_symbols(Symbol_visitor_base*) const; + + // Table of the objects in the group. + std::vector members_; +}; + +// This class is used to pick out the desired elements and add them to the link. + +class Add_lib_group_symbols : public Task +{ + public: + Add_lib_group_symbols(Symbol_table* symtab, Layout* layout, + Input_objects* input_objects, + Lib_group* lib, Task_token* next_blocker) + : symtab_(symtab), layout_(layout), input_objects_(input_objects), + lib_(lib), readsyms_blocker_(NULL), this_blocker_(NULL), + next_blocker_(next_blocker) + { } + + ~Add_lib_group_symbols(); + + // The standard Task methods. + + Task_token* + is_runnable(); + + void + locks(Task_locker*); + + void + run(Workqueue*); + + // Set the blocker to use for this task. + void + set_blocker(Task_token* readsyms_blocker, Task_token* this_blocker) + { + gold_assert(this->readsyms_blocker_ == NULL && this->this_blocker_ == NULL); + this->readsyms_blocker_ = readsyms_blocker; + this->this_blocker_ = this_blocker; + } + + std::string + get_name() const + { + return "Add_lib_group_symbols"; + } + + private: + Symbol_table* symtab_; + Layout* layout_; + Input_objects* input_objects_; + Lib_group* lib_; + Task_token* readsyms_blocker_; + Task_token* this_blocker_; + Task_token* next_blocker_; +}; + +} // End namespace gold. + +#endif // !defined(GOLD_ARCHIVE_H) diff --git a/binutils-2.25/gold/arm-reloc-property.cc b/binutils-2.25/gold/arm-reloc-property.cc new file mode 100644 index 00000000..3259c40b --- /dev/null +++ b/binutils-2.25/gold/arm-reloc-property.cc @@ -0,0 +1,333 @@ +// arm-reloc-property.cc -- ARM relocation property. + +// Copyright 2010 Free Software Foundation, Inc. +// Written by Doug Kwan . + +// 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 +#include +#include +#include +#include + +#include "elfcpp.h" +#include "arm.h" +#include "arm-reloc-property.h" + +namespace gold +{ + +// Arm_reloc_property::Tree_node methods. + +// Parse an S-expression S and build a tree and return the root node. +// Caller is responsible for releasing tree after use. + +Arm_reloc_property::Tree_node* +Arm_reloc_property::Tree_node::make_tree(const std::string& s) +{ + std::stack size_stack; + Tree_node_vector node_stack; + + // strtok needs a non-const string pointer. + char* buffer = new char[s.size() + 1]; + memcpy(buffer, s.data(), s.size()); + buffer[s.size()] = '\0'; + char* token = strtok(buffer, " "); + + while (token != NULL) + { + if (strcmp(token, "(") == 0) + // Remember the node stack position for start of a new internal node. + size_stack.push(node_stack.size()); + else if (strcmp(token, ")") == 0) + { + // Pop all tree nodes after the previous '(' and use them as + // children to build a new internal node. Push internal node back. + size_t current_size = node_stack.size(); + size_t prev_size = size_stack.top(); + size_stack.pop(); + Tree_node* node = + new Tree_node(node_stack.begin() + prev_size, + node_stack.begin() + current_size); + node_stack.resize(prev_size); + node_stack.push_back(node); + } + else + // Just push a leaf node to node_stack. + node_stack.push_back(new Tree_node(token)); + + token = strtok(NULL, " "); + } + + delete[] buffer; + + // At this point, size_stack should be empty and node_stack should only + // contain the root node. + gold_assert(size_stack.empty() && node_stack.size() == 1); + return node_stack[0]; +} + +// Arm_reloc_property methods. + +// Constructor. + +Arm_reloc_property::Arm_reloc_property( + unsigned int code, + const char* name, + Reloc_type rtype, + bool is_deprecated, + Reloc_class rclass, + const std::string& operation, + bool is_implemented, + int group_index, + bool checks_overflow) + : code_(code), name_(name), reloc_type_(rtype), reloc_class_(rclass), + group_index_(group_index), size_(0), align_(1), + relative_address_base_(RAB_NONE), is_deprecated_(is_deprecated), + is_implemented_(is_implemented), checks_overflow_(checks_overflow), + uses_got_entry_(false), uses_got_origin_(false), uses_plt_entry_(false), + uses_thumb_bit_(false), uses_symbol_base_(false), uses_addend_(false), + uses_symbol_(false) +{ + // Set size and alignment of static and dynamic relocations. + if (rtype == RT_STATIC) + { + switch (rclass) + { + case RC_DATA: + // Except for R_ARM_ABS16 and R_ARM_ABS8, all static data relocations + // have size 4. All static data relocations have alignment of 1. + if (code == elfcpp::R_ARM_ABS8) + this->size_ = 1; + else if (code == elfcpp::R_ARM_ABS16) + this->size_ = 2; + else + this->size_ = 4; + this->align_ = 1; + break; + case RC_MISC: + // R_ARM_V4BX should be treated as an ARM relocation. For all + // others, just use defaults. + if (code != elfcpp::R_ARM_V4BX) + break; + // Fall through. + case RC_ARM: + this->size_ = 4; + this->align_ = 4; + break; + case RC_THM16: + this->size_ = 2; + this->align_ = 2; + break; + case RC_THM32: + this->size_ = 4; + this->align_ = 2; + break; + default: + gold_unreachable(); + } + } + else if (rtype == RT_DYNAMIC) + { + // With the exception of R_ARM_COPY, all dynamic relocations requires + // that the place being relocated is a word-aligned 32-bit object. + if (code != elfcpp::R_ARM_COPY) + { + this->size_ = 4; + this->align_ = 4; + } + } + + // If no relocation operation is specified, we are done. + if (operation == "NONE") + return; + + // Extract information from relocation operation. + Tree_node* root_node = Tree_node::make_tree(operation); + Tree_node* node = root_node; + + // Check for an expression of the form XXX - YYY. + if (!node->is_leaf() + && node->child(0)->is_leaf() + && node->child(0)->name() == "-") + { + struct RAB_table_entry + { + Relative_address_base rab; + const char* name; + }; + + static const RAB_table_entry rab_table[] = + { + { RAB_B_S, "( B S )" }, + { RAB_DELTA_B_S, "( DELTA_B ( S ) )" }, + { RAB_GOT_ORG, "GOT_ORG" }, + { RAB_P, "P" }, + { RAB_Pa, "Pa" }, + { RAB_TLS, "TLS" }, + { RAB_tp, "tp" } + }; + + static size_t rab_table_size = sizeof(rab_table) / sizeof(rab_table[0]); + const std::string rhs(node->child(2)->s_expression()); + for (size_t i = 0; i < rab_table_size; ++i) + if (rhs == rab_table[i].name) + { + this->relative_address_base_ = rab_table[i].rab; + break; + } + + gold_assert(this->relative_address_base_ != RAB_NONE); + if (this->relative_address_base_ == RAB_B_S) + this->uses_symbol_base_ = true; + node = node->child(1); + } + + // Check for an expression of the form XXX | T. + if (!node->is_leaf() + && node->child(0)->is_leaf() + && node->child(0)->name() == "|") + { + gold_assert(node->number_of_children() == 3 + && node->child(2)->is_leaf() + && node->child(2)->name() == "T"); + this->uses_thumb_bit_ = true; + node = node->child(1); + } + + // Check for an expression of the form XXX + A. + if (!node->is_leaf() + && node->child(0)->is_leaf() + && node->child(0)->name() == "+") + { + gold_assert(node->number_of_children() == 3 + && node->child(2)->is_leaf() + && node->child(2)->name() == "A"); + this->uses_addend_ = true; + node = node->child(1); + } + + // Check for an expression of the form XXX(S). + if (!node->is_leaf() && node->child(0)->is_leaf()) + { + gold_assert(node->number_of_children() == 2 + && node->child(1)->is_leaf() + && node->child(1)->name() == "S"); + const std::string func(node->child(0)->name()); + if (func == "B") + this->uses_symbol_base_ = true; + else if (func == "GOT") + this->uses_got_entry_ = true; + else if (func == "PLT") + this->uses_plt_entry_ = true; + else if (func == "Module" || func == "DELTA_B") + // These are used in dynamic relocations. + ; + else + gold_unreachable(); + node = node->child(1); + } + + gold_assert(node->is_leaf() && node->name() == "S"); + this->uses_symbol_ = true; + + delete root_node; +} + +// Arm_reloc_property_table methods. + +// Constructor. This processing informations in arm-reloc.def to +// initialize the table. + +Arm_reloc_property_table::Arm_reloc_property_table() +{ + // These appear in arm-reloc.def. Do not rename them. + Parse_expression A("A"), GOT_ORG("GOT_ORG"), NONE("NONE"), P("P"), + Pa("Pa"), S("S"), T("T"), TLS("TLS"), tp("tp"); + const bool Y(true), N(false); + + for (unsigned int i = 0; i < Property_table_size; ++i) + this->table_[i] = NULL; + +#undef RD +#define RD(name, type, deprecated, class, operation, is_implemented, \ + group_index, checks_oveflow) \ + do \ + { \ + unsigned int code = elfcpp::R_ARM_##name; \ + gold_assert(code < Property_table_size); \ + this->table_[code] = \ + new Arm_reloc_property(elfcpp::R_ARM_##name, "R_ARM_" #name, \ + Arm_reloc_property::RT_##type, deprecated, \ + Arm_reloc_property::RC_##class, \ + (operation).s_expression(), is_implemented, \ + group_index, checks_oveflow); \ + } \ + while(0); + +#include "arm-reloc.def" +#undef RD +} + +// Return a string describing a relocation code that fails to get a +// relocation property in get_implemented_static_reloc_property(). + +std::string +Arm_reloc_property_table::reloc_name_in_error_message(unsigned int code) +{ + gold_assert(code < Property_table_size); + + const Arm_reloc_property* arp = this->table_[code]; + + if (arp == NULL) + { + char buffer[100]; + sprintf(buffer, _("invalid reloc %u"), code); + return std::string(buffer); + } + + // gold only implements static relocation codes. + Arm_reloc_property::Reloc_type reloc_type = arp->reloc_type(); + gold_assert(reloc_type == Arm_reloc_property::RT_STATIC + || !arp->is_implemented()); + + const char* prefix = NULL; + switch (reloc_type) + { + case Arm_reloc_property::RT_STATIC: + prefix = arp->is_implemented() ? _("reloc ") : _("unimplemented reloc "); + break; + case Arm_reloc_property::RT_DYNAMIC: + prefix = _("dynamic reloc "); + break; + case Arm_reloc_property::RT_PRIVATE: + prefix = _("private reloc "); + break; + case Arm_reloc_property::RT_OBSOLETE: + prefix = _("obsolete reloc "); + break; + default: + gold_unreachable(); + } + return std::string(prefix) + arp->name(); +} + +} // End namespace gold. diff --git a/binutils-2.25/gold/arm-reloc-property.h b/binutils-2.25/gold/arm-reloc-property.h new file mode 100644 index 00000000..afba2934 --- /dev/null +++ b/binutils-2.25/gold/arm-reloc-property.h @@ -0,0 +1,386 @@ +// arm-reloc-property.h -- ARM relocation properties -*- C++ -*- + +// Copyright 2010 Free Software Foundation, Inc. +// Written by Doug Kwan . + +// 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. + +#ifndef GOLD_ARM_RELOC_PROPERTY_H +#define GOLD_ARM_RELOC_PROPERTY_H + +namespace gold +{ +// The Arm_reloc_property class is to store information about a particular +// relocation code. + +class Arm_reloc_property +{ + public: + // Types of relocation codes. + enum Reloc_type { + RT_NONE, // No relocation type. + RT_STATIC, // Relocations processed by static linkers. + RT_DYNAMIC, // Relocations processed by dynamic linkers. + RT_PRIVATE, // Private relocations, not supported by gold. + RT_OBSOLETE // Obsolete relocations that should not be used. + }; + + // Classes of relocation codes. + enum Reloc_class { + RC_NONE, // No relocation class. + RC_DATA, // Data relocation. + RC_ARM, // ARM instruction relocation. + RC_THM16, // 16-bit THUMB instruction relocation. + RC_THM32, // 32-bit THUMB instruction relocation. + RC_MISC // Miscellaneous class. + }; + + // Types of bases of relative addressing relocation codes. + enum Relative_address_base { + RAB_NONE, // Relocation is not relative addressing + RAB_B_S, // Address origin of output segment of defining symbol. + RAB_DELTA_B_S, // Change of address origin. + RAB_GOT_ORG, // Origin of GOT. + RAB_P, // Address of the place being relocated. + RAB_Pa, // Adjusted address (P & 0xfffffffc). + RAB_TLS, // Thread local storage. + RAB_tp // Thread pointer. + }; + + // Relocation code represented by this. + unsigned int + code() const + { return this->code_; } + + // Name of the relocation code. + const std::string& + name() const + { return this->name_; } + + // Type of relocation code. + Reloc_type + reloc_type() const + { return this->reloc_type_; } + + // Whether this code is deprecated. + bool + is_deprecated() const + { return this->is_deprecated_; } + + // Class of relocation code. + Reloc_class + reloc_class() const + { return this->reloc_class_; } + + // Whether this code is implemented in gold. + bool + is_implemented() const + { return this->is_implemented_; } + + // If code is a group relocation code, return the group number, otherwise -1. + int + group_index() const + { return this->group_index_; } + + // Whether relocation checks for overflow. + bool + checks_overflow() const + { return this->checks_overflow_; } + + // Return size of relocation. + size_t + size() const + { return this->size_; } + + // Return alignment of relocation. + size_t + align() const + { return this->align_; } + + // Whether relocation use a GOT entry. + bool + uses_got_entry() const + { return this->uses_got_entry_; } + + // Whether relocation use a GOT origin. + bool + uses_got_origin() const + { return this->uses_got_origin_; } + + // Whether relocation uses the Thumb-bit in a symbol address. + bool + uses_thumb_bit() const + { return this->uses_thumb_bit_; } + + // Whether relocation uses the symbol base. + bool + uses_symbol_base() const + { return this->uses_symbol_base_; } + + // Whether relocation uses the symbol. + bool + uses_symbol() const + { return this->uses_symbol_; } + + // Return the type of relative address base or RAB_NONE if this + // is not a relative addressing relocation. + Relative_address_base + relative_address_base() const + { return this->relative_address_base_; } + + protected: + // These are protected. We only allow Arm_reloc_property_table to + // manage Arm_reloc_property. + Arm_reloc_property(unsigned int code, const char* name, Reloc_type rtype, + bool is_deprecated, Reloc_class rclass, + const std::string& operation, bool is_implemented, + int group_index, bool checks_overflow); + + friend class Arm_reloc_property_table; + + private: + // Copying is not allowed. + Arm_reloc_property(const Arm_reloc_property&); + Arm_reloc_property& operator=(const Arm_reloc_property&); + + // The Tree_node class is used to represent parsed relocation operations. + // We look at Trees to extract information about relocation operations. + class Tree_node + { + public: + typedef std::vector Tree_node_vector; + + // Construct a leaf node. + Tree_node(const char* name) + : is_leaf_(true), name_(name), children_() + { } + + // Construct an internal node. A node owns all its children and is + // responsible for releasing them at its own destruction. + Tree_node(Tree_node_vector::const_iterator begin, + Tree_node_vector::const_iterator end) + : is_leaf_(false), name_(), children_() + { + for (Tree_node_vector::const_iterator p = begin; p != end; ++p) + this->children_.push_back(*p); + } + + ~Tree_node() + { + for(size_t i = 0; i children_.size(); ++i) + delete this->children_[i]; + } + + // Whether this is a leaf node. + bool + is_leaf() const + { return this->is_leaf_; } + + // Return name of this. This is only valid for a leaf node. + const std::string& + name() const + { + gold_assert(this->is_leaf_); + return this->name_; + } + + // Return the number of children. This is only valid for a non-leaf node. + size_t + number_of_children() const + { + gold_assert(!this->is_leaf_); + return this->children_.size(); + } + + // Return the i-th child of this. This is only valid for a non-leaf node. + Tree_node* + child(size_t i) const + { + gold_assert(!this->is_leaf_ && i < this->children_.size()); + return this->children_[i]; + } + + // Parse an S-expression string and build a tree and return the root node. + // Caller is responsible for releasing tree after use. + static Tree_node* + make_tree(const std::string&); + + // Convert a tree back to an S-expression string. + std::string + s_expression() const + { + if (this->is_leaf_) + return this->name_; + + // Concatenate S-expressions of children. Enclose them with + // a pair of parentheses and use space as token delimiters. + std::string s("("); + for(size_t i = 0; i children_.size(); ++i) + s = s + " " + this->children_[i]->s_expression(); + return s + " )"; + } + + private: + // Whether this is a leaf node. + bool is_leaf_; + // Name of this if this is a leaf node. + std::string name_; + // Children of this if this a non-leaf node. + Tree_node_vector children_; + }; + + // Relocation code. + unsigned int code_; + // Relocation name. + std::string name_; + // Type of relocation. + Reloc_type reloc_type_; + // Class of relocation. + Reloc_class reloc_class_; + // Group index (0, 1, or 2) if this is a group relocation or -1 otherwise. + int group_index_; + // Size of relocation. + size_t size_; + // Alignment of relocation. + size_t align_; + // Relative address base. + Relative_address_base relative_address_base_; + // Whether this is deprecated. + bool is_deprecated_ : 1; + // Whether this is implemented in gold. + bool is_implemented_ : 1; + // Whether this checks overflow. + bool checks_overflow_ : 1; + // Whether this uses a GOT entry. + bool uses_got_entry_ : 1; + // Whether this uses a GOT origin. + bool uses_got_origin_ : 1; + // Whether this uses a PLT entry. + bool uses_plt_entry_ : 1; + // Whether this uses the THUMB bit in symbol address. + bool uses_thumb_bit_ : 1; + // Whether this uses the symbol base. + bool uses_symbol_base_ : 1; + // Whether this uses an addend. + bool uses_addend_ : 1; + // Whether this uses the symbol. + bool uses_symbol_ : 1; +}; + +// Arm_reloc_property_table. This table is used for looking up properties +// of relocation types. The table entries are initialized using information +// from arm-reloc.def. + +class Arm_reloc_property_table +{ + public: + Arm_reloc_property_table(); + + // Return an Arm_reloc_property object for CODE if it is a valid relocation + // code or NULL otherwise. + const Arm_reloc_property* + get_reloc_property(unsigned int code) const + { + gold_assert(code < Property_table_size); + return this->table_[code]; + } + + // Like get_reloc_property but only return non-NULL if relocation code is + // static and implemented. + const Arm_reloc_property* + get_implemented_static_reloc_property(unsigned int code) const + { + gold_assert(code < Property_table_size); + const Arm_reloc_property* arp = this->table_[code]; + return ((arp != NULL + && (arp->reloc_type() == Arm_reloc_property::RT_STATIC) + && arp->is_implemented()) + ? arp + : NULL); + } + + // Return a string describing the relocation code that is not + // an implemented static reloc code. + std::string + reloc_name_in_error_message(unsigned int code); + + private: + // Copying is not allowed. + Arm_reloc_property_table(const Arm_reloc_property_table&); + Arm_reloc_property_table& operator=(const Arm_reloc_property_table&); + + // The Parse_expression class is used to convert relocation operations in + // arm-reloc.def into S-expression strings, which are parsed again to + // build actual expression trees. We do not build the expression trees + // directly because the parser for operations in arm-reloc.def is simpler + // this way. Conversion from S-expressions to trees is simple. + class Parse_expression + { + public: + // Construction a Parse_expression with an S-expression string. + Parse_expression(const std::string& s_expression) + : s_expression_(s_expression) + { } + + // Value of this expression as an S-expression string. + const std::string& + s_expression() const + { return this->s_expression_; } + + // We want to overload operators used in relocation operations so + // that we can execute operations in arm-reloc.def to generate + // S-expressions directly. +#define DEF_OPERATOR_OVERLOAD(op) \ + Parse_expression \ + operator op (const Parse_expression& e) \ + { \ + return Parse_expression("( " #op " " + this->s_expression_ + " " + \ + e.s_expression_ + " )"); \ + } + + // Operator appearing in relocation operations in arm-reloc.def. + DEF_OPERATOR_OVERLOAD(+) + DEF_OPERATOR_OVERLOAD(-) + DEF_OPERATOR_OVERLOAD(|) + + private: + // This represented as an S-expression string. + std::string s_expression_; + }; + +#define DEF_RELOC_FUNC(name) \ + static Parse_expression \ + (name)(const Parse_expression& arg) \ + { return Parse_expression("( " #name " " + arg.s_expression() + " )"); } + + // Functions appearing in relocation operations in arm-reloc.def. + DEF_RELOC_FUNC(B) + DEF_RELOC_FUNC(DELTA_B) + DEF_RELOC_FUNC(GOT) + DEF_RELOC_FUNC(Module) + DEF_RELOC_FUNC(PLT) + + static const unsigned int Property_table_size = 256; + + // The property table. + Arm_reloc_property* table_[Property_table_size]; +}; + +} // End namespace gold. + +#endif // !defined(GOLD_ARM_RELOC_PROPERTY_H) diff --git a/binutils-2.25/gold/arm-reloc.def b/binutils-2.25/gold/arm-reloc.def new file mode 100644 index 00000000..3a5ab6ce --- /dev/null +++ b/binutils-2.25/gold/arm-reloc.def @@ -0,0 +1,194 @@ +// arm-reloc.def -- ARM relocation definitions. + +// Copyright 2010 Free Software Foundation, Inc. +// Written by Doug Kwan . + +// 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. + +// The information here is based on the official ARM document "ELF for ARM +// Architecture" (Document number ARM IHI 0044C). The first five columns of +// the table below are derived from Table 4-8 in the ARM ELF document. Each +// relocation from Table 4-8 corresponds to one relocation definition in the +// table below. A relocation definition has the following information: +// +// Name: This is the name of the relocation without the "R_ARM_" prefix. +// +// Type: Relocation type. There are four. +// - STATIC for static relocations processed by a static linker. +// - DYNAMIC for dynamic relocations processed by a dynamic linker. +// - PRIVATE for R_ARM_PRIVATE_ private relocation type. +// - OBSOLETE for old relocation types no longer used. +// We do not use DEPRECATED as a distinct type since we still have to +// handle deprecated relocations so we one of the types above. +// +// Deprecated: Whether this is a deprecated relocation type. The linker +// is expected to handle these though they should not be generated by fully +// conforming tool-chains. +// +// Operation: An expression specifying how the linker should perform a +// relocation. If there is no operation or the operation cannot be +// specified, it is "NONE". +// +// Implemented: Whether this is implemented by the gold. +// +// Group_index: For a group relocation type, it is one of 0, 1 or 2. For +// a non-group relocation type, it is -1. +// +// Overflow: Whether gold should check for overflow. This is "No" by default +// for relocation types DYNAMIC, PRIVATE and OBSOLETE. +// +// Overflow-----------------------------------------------------------------+ +// Group index----------------------------------------------------------+ | +// Implemented-------------------------------------------------------+ | | +// Operation-------------------------------+ | | | +// Class----------------------------+ | | | | +// Deprecated--------------------+ | | | | | +// Type----------------+ | | | | | | +// Name | | | | | | | +// | | | | | | | | +RD(NONE , STATIC , N, MISC , NONE , Y, -1, N) +RD(PC24 , STATIC , Y, ARM , ((S + A) | T) - P , Y, -1, Y) +RD(ABS32 , STATIC , N, DATA , (S + A) | T , Y, -1, N) +RD(REL32 , STATIC , N, DATA , ((S + A) | T) - P , Y, -1, N) +RD(LDR_PC_G0 , STATIC , N, ARM , S + A - P , Y, 0, Y) +RD(ABS16 , STATIC , N, DATA , S + A , Y, -1, Y) +RD(ABS12 , STATIC , N, ARM , S + A , Y, -1, Y) +RD(THM_ABS5 , STATIC , N, THM16, S + A , Y, -1, Y) +RD(ABS8 , STATIC , N, DATA , S + A , Y, -1, Y) +RD(SBREL32 , STATIC , N, DATA , ((S + A) | T) - B(S) , N, -1, N) +RD(THM_CALL , STATIC , N, THM32, ((S + A) | T) - P , Y, -1, Y) +RD(THM_PC8 , STATIC , N, THM16, S + A - Pa , Y, -1, Y) +RD(BREL_ADJ , DYNAMIC , N, DATA , DELTA_B(S) + A , Y, -1, N) +RD(TLS_DESC , DYNAMIC , N, DATA , NONE , Y, -1, N) +RD(THM_SWI8 , OBSOLETE, N, NONE , NONE , N, -1, N) +RD(XPC25 , OBSOLETE, N, NONE , NONE , N, -1, N) +RD(THM_XPC22 , OBSOLETE, N, NONE , NONE , N, -1, N) +RD(TLS_DTPMOD32 , DYNAMIC , N, DATA , Module(S) , Y, -1, N) +RD(TLS_DTPOFF32 , DYNAMIC , N, DATA , S + A - TLS , Y, -1, N) +RD(TLS_TPOFF32 , DYNAMIC , N, DATA , S + A - tp , Y, -1, N) +RD(COPY , DYNAMIC , N, MISC , NONE , Y, -1, N) +RD(GLOB_DAT , DYNAMIC , N, DATA , (S + A) | T , Y, -1, N) +RD(JUMP_SLOT , DYNAMIC , N, DATA , (S + A) | T , Y, -1, N) +RD(RELATIVE , DYNAMIC , N, DATA , B(S) + A , Y, -1, N) +RD(GOTOFF32 , STATIC , N, DATA , ((S + A) | T) - GOT_ORG, Y, -1, N) +RD(BASE_PREL , STATIC , N, DATA , B(S) + A - P , Y, -1, N) +RD(GOT_BREL , STATIC , N, DATA , GOT(S) + A - GOT_ORG , Y, -1, N) +RD(PLT32 , STATIC , Y, ARM , ((S + A) | T) - P , Y, -1, Y) +RD(CALL , STATIC , N, ARM , ((S + A) | T) - P , Y, -1, Y) +RD(JUMP24 , STATIC , N, ARM , ((S + A) | T) - P , Y, -1, Y) +RD(THM_JUMP24 , STATIC , N, THM32, ((S + A) | T) - P , Y, -1, Y) +RD(BASE_ABS , STATIC , N, DATA , B(S) + A , Y, -1, N) +RD(ALU_PCREL_7_0 , OBSOLETE, N, NONE , NONE , N, -1, N) +RD(ALU_PCREL_15_8 , OBSOLETE, N, NONE , NONE , N, -1, N) +RD(ALU_PCREL_23_15 , OBSOLETE, N, NONE , NONE , N, -1, N) +RD(LDR_SBREL_11_0_NC , STATIC , Y, ARM , S + A - B(S) , N, -1, N) +RD(ALU_SBREL_19_12_NC, STATIC , Y, ARM , S + A - B(S) , N, -1, N) +RD(ALU_SBREL_27_20_CK, STATIC , Y, ARM , S + A - B(S) , N, -1, Y) +RD(TARGET1 , STATIC , N, MISC , NONE , Y, -1, N) +RD(SBREL31 , STATIC , Y, DATA , ((S + A) | T) - B(S) , N, -1, N) +RD(V4BX , STATIC , N, MISC , NONE , Y, -1, N) +RD(TARGET2 , STATIC , N, MISC , NONE , Y, -1, N) +RD(PREL31 , STATIC , N, DATA , ((S + A) | T) - P , Y, -1, Y) +RD(MOVW_ABS_NC , STATIC , N, ARM , (S + A) | T , Y, -1, N) +RD(MOVT_ABS , STATIC , N, ARM , S + A , Y, -1, Y) +RD(MOVW_PREL_NC , STATIC , N, ARM , ((S + A) | T) - P , Y, -1, N) +RD(MOVT_PREL , STATIC , N, ARM , (S + A) - P , Y, -1, Y) +RD(THM_MOVW_ABS_NC , STATIC , N, THM32, (S + A) | T , Y, -1, N) +RD(THM_MOVT_ABS , STATIC , N, THM32, S + A , Y, -1, N) +RD(THM_MOVW_PREL_NC , STATIC , N, THM32, ((S + A) | T) - P , Y, -1, N) +RD(THM_MOVT_PREL , STATIC , N, THM32, S + A - P , Y, -1, N) +RD(THM_JUMP19 , STATIC , N, THM32, ((S + A) | T) - P , Y, -1, Y) +RD(THM_JUMP6 , STATIC , N, THM16, S + A - P , Y, -1, Y) +RD(THM_ALU_PREL_11_0 , STATIC , N, THM32, ((S + A) | T) - Pa , Y, -1, Y) +RD(THM_PC12 , STATIC , N, THM32, S + A - Pa , Y, -1, Y) +RD(ABS32_NOI , STATIC , N, DATA , S + A , Y, -1, N) +RD(REL32_NOI , STATIC , N, DATA , S + A - P , N, -1, N) +RD(ALU_PC_G0_NC , STATIC , N, ARM , ((S + A) | T) - P , Y, 0, N) +RD(ALU_PC_G0 , STATIC , N, ARM , ((S + A) | T) - P , Y, 0, Y) +RD(ALU_PC_G1_NC , STATIC , N, ARM , ((S + A) | T) - P , Y, 1, N) +RD(ALU_PC_G1 , STATIC , N, ARM , ((S + A) | T) - P , Y, 1, Y) +RD(ALU_PC_G2 , STATIC , N, ARM , ((S + A) | T) - P , Y, 2, Y) +RD(LDR_PC_G1 , STATIC , N, ARM , S + A - P , Y, 1, Y) +RD(LDR_PC_G2 , STATIC , N, ARM , S + A - P , Y, 2, Y) +RD(LDRS_PC_G0 , STATIC , N, ARM , S + A - P , Y, 0, Y) +RD(LDRS_PC_G1 , STATIC , N, ARM , S + A - P , Y, 1, Y) +RD(LDRS_PC_G2 , STATIC , N, ARM , S + A - P , Y, 2, Y) +RD(LDC_PC_G0 , STATIC , N, ARM , S + A - P , Y, 0, Y) +RD(LDC_PC_G1 , STATIC , N, ARM , S + A - P , Y, 1, Y) +RD(LDC_PC_G2 , STATIC , N, ARM , S + A - P , Y, 2, Y) +RD(ALU_SB_G0_NC , STATIC , N, ARM , ((S + A) | T) - B(S) , Y, 0, N) +RD(ALU_SB_G0 , STATIC , N, ARM , ((S + A) | T) - B(S) , Y, 0, Y) +RD(ALU_SB_G1_NC , STATIC , N, ARM , ((S + A) | T) - B(S) , Y, 1, N) +RD(ALU_SB_G1 , STATIC , N, ARM , ((S + A) | T) - B(S) , Y, 1, Y) +RD(ALU_SB_G2 , STATIC , N, ARM , ((S + A) | T) - B(S) , Y, 2, Y) +RD(LDR_SB_G0 , STATIC , N, ARM , S + A - B(S) , Y, 0, Y) +RD(LDR_SB_G1 , STATIC , N, ARM , S + A - B(S) , Y, 1, Y) +RD(LDR_SB_G2 , STATIC , N, ARM , S + A - B(S) , Y, 2, Y) +RD(LDRS_SB_G0 , STATIC , N, ARM , S + A - B(S) , Y, 0, Y) +RD(LDRS_SB_G1 , STATIC , N, ARM , S + A - B(S) , Y, 1, Y) +RD(LDRS_SB_G2 , STATIC , N, ARM , S + A - B(S) , Y, 2, Y) +RD(LDC_SB_G0 , STATIC , N, ARM , S + A - B(S) , Y, 0, Y) +RD(LDC_SB_G1 , STATIC , N, ARM , S + A - B(S) , Y, 1, Y) +RD(LDC_SB_G2 , STATIC , N, ARM , S + A - B(S) , Y, 2, Y) +RD(MOVW_BREL_NC , STATIC , N, ARM , ((S + A) | T) - B(S) , Y, -1, N) +RD(MOVT_BREL , STATIC , N, ARM , S + A - B(S) , Y, -1, Y) +RD(MOVW_BREL , STATIC , N, ARM , ((S + A) | T) - B(S) , Y, -1, Y) +RD(THM_MOVW_BREL_NC , STATIC , N, THM32, ((S + A) | T) - B(S) , Y, -1, N) +RD(THM_MOVT_BREL , STATIC , N, THM32, S + A - B(S) , Y, -1, N) +RD(THM_MOVW_BREL , STATIC , N, THM32, ((S + A) | T) - B(S) , Y, -1, Y) +RD(TLS_GOTDESC , STATIC , N, DATA , NONE , Y, -1, N) +RD(TLS_CALL , STATIC , N, ARM , NONE , N, -1, Y) +RD(TLS_DESCSEQ , STATIC , N, ARM , NONE , N, -1, Y) +RD(THM_TLS_CALL , STATIC , N, THM32, NONE , N, -1, Y) +RD(PLT32_ABS , STATIC , N, DATA , PLT(S) + A , N, -1, N) +RD(GOT_ABS , STATIC , N, DATA , GOT(S) + A , N, -1, N) +RD(GOT_PREL , STATIC , N, DATA , GOT(S) + A - P , Y, -1, N) +RD(GOT_BREL12 , STATIC , N, ARM , GOT(S) + A - GOT_ORG , N, -1, Y) +RD(GOTOFF12 , STATIC , N, ARM , S + A - GOT_ORG , N, -1, Y) +RD(GOTRELAX , STATIC , N, MISC , NONE , N, -1, N) +RD(GNU_VTENTRY , STATIC , Y, DATA , NONE , Y, -1, N) +RD(GNU_VTINHERIT , STATIC , Y, DATA , NONE , Y, -1, N) +RD(THM_JUMP11 , STATIC , N, THM16, S + A - P , Y, -1, Y) +RD(THM_JUMP8 , STATIC , N, THM16, S + A - P , Y, -1, Y) +RD(TLS_GD32 , STATIC , N, DATA , GOT(S) + A - P , Y, -1, N) +RD(TLS_LDM32 , STATIC , N, DATA , GOT(S) + A - P , Y, -1, N) +RD(TLS_LDO32 , STATIC , N, DATA , S + A - TLS , Y, -1, N) +RD(TLS_IE32 , STATIC , N, DATA , GOT(S) + A - P , Y, -1, N) +RD(TLS_LE32 , STATIC , N, DATA , S + A - tp , Y, -1, N) +RD(TLS_LDO12 , STATIC , N, ARM , S + A - TLS , N, -1, Y) +RD(TLS_LE12 , STATIC , N, ARM , S + A - tp , N, -1, Y) +RD(TLS_IE12GP , STATIC , N, ARM , GOT(S) + A - GOT_ORG , N, -1, Y) +RD(PRIVATE_0 , PRIVATE , N, NONE , NONE , N, -1, N) +RD(PRIVATE_1 , PRIVATE , N, NONE , NONE , N, -1, N) +RD(PRIVATE_2 , PRIVATE , N, NONE , NONE , N, -1, N) +RD(PRIVATE_3 , PRIVATE , N, NONE , NONE , N, -1, N) +RD(PRIVATE_4 , PRIVATE , N, NONE , NONE , N, -1, N) +RD(PRIVATE_5 , PRIVATE , N, NONE , NONE , N, -1, N) +RD(PRIVATE_6 , PRIVATE , N, NONE , NONE , N, -1, N) +RD(PRIVATE_7 , PRIVATE , N, NONE , NONE , N, -1, N) +RD(PRIVATE_8 , PRIVATE , N, NONE , NONE , N, -1, N) +RD(PRIVATE_9 , PRIVATE , N, NONE , NONE , N, -1, N) +RD(PRIVATE_10 , PRIVATE , N, NONE , NONE , N, -1, N) +RD(PRIVATE_11 , PRIVATE , N, NONE , NONE , N, -1, N) +RD(PRIVATE_12 , PRIVATE , N, NONE , NONE , N, -1, N) +RD(PRIVATE_13 , PRIVATE , N, NONE , NONE , N, -1, N) +RD(PRIVATE_14 , PRIVATE , N, NONE , NONE , N, -1, N) +RD(PRIVATE_15 , PRIVATE , N, NONE , NONE , N, -1, N) +RD(ME_TOO , OBSOLETE, N, NONE , NONE , N, -1, N) +RD(THM_TLS_DESCSEQ16 , STATIC , N, THM16, NONE , N, -1, Y) +RD(THM_TLS_DESCSEQ32 , STATIC , N, THM32, NONE , N, -1, Y) diff --git a/binutils-2.25/gold/arm.cc b/binutils-2.25/gold/arm.cc new file mode 100644 index 00000000..560f3807 --- /dev/null +++ b/binutils-2.25/gold/arm.cc @@ -0,0 +1,12387 @@ +// arm.cc -- arm target support for gold. + +// Copyright 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc. +// Written by Doug Kwan based on the i386 code +// by Ian Lance Taylor . +// This file also contains borrowed and adapted code from +// bfd/elf32-arm.c. + +// 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 +#include +#include +#include +#include +#include +#include +#include + +#include "elfcpp.h" +#include "parameters.h" +#include "reloc.h" +#include "arm.h" +#include "object.h" +#include "symtab.h" +#include "layout.h" +#include "output.h" +#include "copy-relocs.h" +#include "target.h" +#include "target-reloc.h" +#include "target-select.h" +#include "tls.h" +#include "defstd.h" +#include "gc.h" +#include "attributes.h" +#include "arm-reloc-property.h" +#include "nacl.h" + +namespace +{ + +using namespace gold; + +template +class Output_data_plt_arm; + +template +class Output_data_plt_arm_standard; + +template +class Stub_table; + +template +class Arm_input_section; + +class Arm_exidx_cantunwind; + +class Arm_exidx_merged_section; + +class Arm_exidx_fixup; + +template +class Arm_output_section; + +class Arm_exidx_input_section; + +template +class Arm_relobj; + +template +class Arm_relocate_functions; + +template +class Arm_output_data_got; + +template +class Target_arm; + +// For convenience. +typedef elfcpp::Elf_types<32>::Elf_Addr Arm_address; + +// Maximum branch offsets for ARM, THUMB and THUMB2. +const int32_t ARM_MAX_FWD_BRANCH_OFFSET = ((((1 << 23) - 1) << 2) + 8); +const int32_t ARM_MAX_BWD_BRANCH_OFFSET = ((-((1 << 23) << 2)) + 8); +const int32_t THM_MAX_FWD_BRANCH_OFFSET = ((1 << 22) -2 + 4); +const int32_t THM_MAX_BWD_BRANCH_OFFSET = (-(1 << 22) + 4); +const int32_t THM2_MAX_FWD_BRANCH_OFFSET = (((1 << 24) - 2) + 4); +const int32_t THM2_MAX_BWD_BRANCH_OFFSET = (-(1 << 24) + 4); + +// Thread Control Block size. +const size_t ARM_TCB_SIZE = 8; + +// The arm target class. +// +// 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 +// Thumb-2 and BE8. +// There are probably a lot more. + +// Ideally we would like to avoid using global variables but this is used +// very in many places and sometimes in loops. If we use a function +// returning a static instance of Arm_reloc_property_table, it will be very +// slow in an threaded environment since the static instance needs to be +// locked. The pointer is below initialized in the +// Target::do_select_as_default_target() hook so that we do not spend time +// building the table if we are not linking ARM objects. +// +// An alternative is to to process the information in arm-reloc.def in +// compilation time and generate a representation of it in PODs only. That +// way we can avoid initialization when the linker starts. + +Arm_reloc_property_table* arm_reloc_property_table = NULL; + +// Instruction template class. This class is similar to the insn_sequence +// struct in bfd/elf32-arm.c. + +class Insn_template +{ + public: + // Types of instruction templates. + enum Type + { + THUMB16_TYPE = 1, + // 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. + THUMB16_SPECIAL_TYPE, + THUMB32_TYPE, + ARM_TYPE, + DATA_TYPE + }; + + // Factory methods to create instruction templates in different formats. + + static const Insn_template + thumb16_insn(uint32_t data) + { 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); } + + static const Insn_template + thumb32_insn(uint32_t data) + { 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) + { return Insn_template(data, ARM_TYPE, elfcpp::R_ARM_NONE, 0); } + + static const Insn_template + arm_rel_insn(unsigned data, int reloc_addend) + { return Insn_template(data, ARM_TYPE, elfcpp::R_ARM_JUMP24, reloc_addend); } + + 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); } + + // Accessors. This class is used for read-only objects so no modifiers + // are provided. + + uint32_t + data() const + { return this->data_; } + + // Return the instruction sequence type of this. + Type + type() const + { return this->type_; } + + // Return the ARM relocation type of this. + unsigned int + r_type() const + { return this->r_type_; } + + int32_t + reloc_addend() const + { return this->reloc_addend_; } + + // Return size of instruction template in bytes. + size_t + size() const; + + // Return byte-alignment of instruction template. + unsigned + alignment() const; + + private: + // We make the constructor private to ensure that only the factory + // methods are used. + inline + Insn_template(unsigned data, Type type, unsigned int r_type, int reloc_addend) + : data_(data), type_(type), r_type_(r_type), reloc_addend_(reloc_addend) + { } + + // Instruction specific data. This is used to store information like + // some of the instruction bits. + uint32_t data_; + // Instruction template type. + Type type_; + // Relocation type if there is a relocation or R_ARM_NONE otherwise. + unsigned int r_type_; + // Relocation addend. + int32_t reloc_addend_; +}; + +// Macro for generating code to stub types. One entry per long/short +// branch stub + +#define DEF_STUBS \ + DEF_STUB(long_branch_any_any) \ + DEF_STUB(long_branch_v4t_arm_thumb) \ + DEF_STUB(long_branch_thumb_only) \ + DEF_STUB(long_branch_v4t_thumb_thumb) \ + DEF_STUB(long_branch_v4t_thumb_arm) \ + DEF_STUB(short_branch_v4t_thumb_arm) \ + DEF_STUB(long_branch_any_arm_pic) \ + DEF_STUB(long_branch_any_thumb_pic) \ + DEF_STUB(long_branch_v4t_thumb_thumb_pic) \ + DEF_STUB(long_branch_v4t_arm_thumb_pic) \ + DEF_STUB(long_branch_v4t_thumb_arm_pic) \ + DEF_STUB(long_branch_thumb_only_pic) \ + DEF_STUB(a8_veneer_b_cond) \ + DEF_STUB(a8_veneer_b) \ + DEF_STUB(a8_veneer_bl) \ + DEF_STUB(a8_veneer_blx) \ + DEF_STUB(v4_veneer_bx) + +// Stub types. + +#define DEF_STUB(x) arm_stub_##x, +typedef enum + { + arm_stub_none, + DEF_STUBS + + // First reloc stub type. + arm_stub_reloc_first = arm_stub_long_branch_any_any, + // Last reloc stub type. + arm_stub_reloc_last = arm_stub_long_branch_thumb_only_pic, + + // First Cortex-A8 stub type. + 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; +#undef DEF_STUB + +// Stub template class. Templates are meant to be read-only objects. +// A stub template for a stub type contains all read-only attributes +// common to all stubs of the same type. + +class Stub_template +{ + public: + Stub_template(Stub_type, const Insn_template*, size_t); + + ~Stub_template() + { } + + // Return stub type. + Stub_type + type() const + { return this->type_; } + + // Return an array of instruction templates. + const Insn_template* + insns() const + { return this->insns_; } + + // Return size of template in number of instructions. + size_t + insn_count() const + { return this->insn_count_; } + + // Return size of template in bytes. + size_t + size() const + { return this->size_; } + + // Return alignment of the stub template. + unsigned + alignment() const + { return this->alignment_; } + + // Return whether entry point is in thumb mode. + bool + entry_in_thumb_mode() const + { return this->entry_in_thumb_mode_; } + + // Return number of relocations in this template. + size_t + reloc_count() const + { return this->relocs_.size(); } + + // Return index of the I-th instruction with relocation. + size_t + reloc_insn_index(size_t i) const + { + gold_assert(i < this->relocs_.size()); + return this->relocs_[i].first; + } + + // Return the offset of the I-th instruction with relocation from the + // beginning of the stub. + section_size_type + reloc_offset(size_t i) const + { + gold_assert(i < this->relocs_.size()); + return this->relocs_[i].second; + } + + private: + // This contains information about an instruction template with a relocation + // and its offset from start of stub. + typedef std::pair Reloc; + + // A Stub_template may not be copied. We want to share templates as much + // 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. + const Insn_template* insns_; + // Number of Insn_templates in insns_[]. + size_t insn_count_; + // Size of templated instructions in bytes. + size_t size_; + // Alignment of templated instructions. + unsigned alignment_; + // Flag to indicate if entry is in thumb mode. + 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. + std::vector relocs_; +}; + +// +// A class for code stubs. This is a base class for different type of +// stubs used in the ARM target. +// + +class Stub +{ + private: + static const section_offset_type invalid_offset = + static_cast(-1); + + public: + Stub(const Stub_template* stub_template) + : stub_template_(stub_template), offset_(invalid_offset) + { } + + virtual + ~Stub() + { } + + // Return the stub template. + const Stub_template* + stub_template() const + { return this->stub_template_; } + + // Return offset of code stub from beginning of its containing stub table. + section_offset_type + offset() const + { + gold_assert(this->offset_ != invalid_offset); + return this->offset_; + } + + // Set offset of code stub from beginning of its containing stub table. + 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 + reloc_target(size_t i) + { return this->do_reloc_target(i); } + + // Write a stub at output VIEW. BIG_ENDIAN select how a stub is written. + void + write(unsigned char* view, section_size_type view_size, bool big_endian) + { this->do_write(view, view_size, big_endian); } + + // Return the instruction for THUMB16_SPECIAL_TYPE instruction template + // for the i-th instruction. + uint16_t + thumb16_special(size_t i) + { return this->do_thumb16_special(i); } + + protected: + // This must be defined in the child class. + virtual Arm_address + do_reloc_target(size_t) = 0; + + // This may be overridden in the child class. + virtual void + do_write(unsigned char* view, section_size_type view_size, bool big_endian) + { + if (big_endian) + this->do_fixed_endian_write(view, view_size); + else + this->do_fixed_endian_write(view, view_size); + } + + // This must be overridden if a child class uses the THUMB16_SPECIAL_TYPE + // instruction template. + virtual uint16_t + do_thumb16_special(size_t) + { gold_unreachable(); } + + private: + // A template to implement do_write. + template + void inline + do_fixed_endian_write(unsigned char*, section_size_type); + + // Its template. + const Stub_template* stub_template_; + // Offset within the section of containing this stub. + section_offset_type offset_; +}; + +// Reloc stub class. These are stubs we use to fix up relocation because +// of limited branch ranges. + +class Reloc_stub : public Stub +{ + public: + static const unsigned int invalid_index = static_cast(-1); + // We assume we never jump to this address. + static const Arm_address invalid_address = static_cast(-1); + + // Return destination address. + Arm_address + destination_address() const + { + gold_assert(this->destination_address_ != this->invalid_address); + return this->destination_address_; + } + + // Set destination address. + void + set_destination_address(Arm_address address) + { + gold_assert(address != this->invalid_address); + this->destination_address_ = address; + } + + // Reset destination address. + void + reset_destination_address() + { this->destination_address_ = this->invalid_address; } + + // Determine stub type for a branch of a relocation of R_TYPE going + // from BRANCH_ADDRESS to BRANCH_TARGET. If TARGET_IS_THUMB is set, + // the branch target is a thumb instruction. TARGET is used for look + // up ARM-specific linker settings. + static Stub_type + stub_type_for_reloc(unsigned int r_type, Arm_address branch_address, + Arm_address branch_target, bool target_is_thumb); + + // Reloc_stub key. A key is logically a triplet of a stub type, a symbol + // and an addend. Since we treat global and local symbol differently, we + // use a Symbol object for a global symbol and a object-index pair for + // a local symbol. + class Key + { + public: + // If SYMBOL is not null, this is a global symbol, we ignore RELOBJ and + // R_SYM. Otherwise, this is a local symbol and RELOBJ must non-NULL + // and R_SYM must not be invalid_index. + Key(Stub_type stub_type, const Symbol* symbol, const Relobj* relobj, + unsigned int r_sym, int32_t addend) + : stub_type_(stub_type), addend_(addend) + { + if (symbol != NULL) + { + this->r_sym_ = Reloc_stub::invalid_index; + this->u_.symbol = symbol; + } + else + { + gold_assert(relobj != NULL && r_sym != invalid_index); + this->r_sym_ = r_sym; + this->u_.relobj = relobj; + } + } + + ~Key() + { } + + // Accessors: Keys are meant to be read-only object so no modifiers are + // provided. + + // Return stub type. + Stub_type + stub_type() const + { return this->stub_type_; } + + // Return the local symbol index or invalid_index. + unsigned int + r_sym() const + { return this->r_sym_; } + + // Return the symbol if there is one. + const Symbol* + symbol() const + { return this->r_sym_ == invalid_index ? this->u_.symbol : NULL; } + + // Return the relobj if there is one. + const Relobj* + relobj() const + { return this->r_sym_ != invalid_index ? this->u_.relobj : NULL; } + + // Whether this equals to another key k. + bool + eq(const Key& k) const + { + return ((this->stub_type_ == k.stub_type_) + && (this->r_sym_ == k.r_sym_) + && ((this->r_sym_ != Reloc_stub::invalid_index) + ? (this->u_.relobj == k.u_.relobj) + : (this->u_.symbol == k.u_.symbol)) + && (this->addend_ == k.addend_)); + } + + // Return a hash value. + size_t + hash_value() const + { + return (this->stub_type_ + ^ this->r_sym_ + ^ gold::string_hash( + (this->r_sym_ != Reloc_stub::invalid_index) + ? this->u_.relobj->name().c_str() + : this->u_.symbol->name()) + ^ this->addend_); + } + + // Functors for STL associative containers. + struct hash + { + size_t + operator()(const Key& k) const + { return k.hash_value(); } + }; + + struct equal_to + { + bool + operator()(const Key& k1, const Key& k2) const + { return k1.eq(k2); } + }; + + // Name of key. This is mainly for debugging. + std::string + name() const; + + private: + // Stub type. + Stub_type stub_type_; + // If this is a local symbol, this is the index in the defining object. + // Otherwise, it is invalid_index for a global symbol. + 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 + // 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. + union + { + const Symbol* symbol; + const Relobj* relobj; + } u_; + // Addend associated with a reloc. + int32_t addend_; + }; + + protected: + // Reloc_stubs are created via a stub factory. So these are protected. + Reloc_stub(const Stub_template* stub_template) + : Stub(stub_template), destination_address_(invalid_address) + { } + + ~Reloc_stub() + { } + + friend class Stub_factory; + + // Return the relocation target address of the i-th relocation in the + // stub. + Arm_address + do_reloc_target(size_t i) + { + // All reloc stub have only one relocation. + gold_assert(i == 0); + return this->destination_address_; + } + + private: + // Address of destination. + Arm_address destination_address_; +}; + +// 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 +// branch. +// 3. The branch follows a 32-bit instruction which is not a branch. +// +// To do the fix up, we need to store the address of the branch instruction +// and its target at least. We also need to store the original branch +// instruction bits for the condition code in a conditional branch. The +// condition code is used in a special instruction template. We also want +// to identify input sections needing Cortex-A8 workaround quickly. We store +// extra information about object and section index of the code section +// containing a branch being fixed up. The information is used to mark +// the code section when we finalize the Cortex-A8 stubs. +// + +class Cortex_a8_stub : public Stub +{ + public: + ~Cortex_a8_stub() + { } + + // Return the object of the code section containing the branch being fixed + // up. + Relobj* + relobj() const + { return this->relobj_; } + + // Return the section index of the code section containing the branch being + // fixed up. + unsigned int + shndx() const + { return this->shndx_; } + + // Return the source address of stub. This is the address of the original + // branch instruction. LSB is 1 always set to indicate that it is a THUMB + // instruction. + Arm_address + source_address() const + { return this->source_address_; } + + // Return the destination address of the stub. This is the branch taken + // address of the original branch instruction. LSB is 1 if it is a THUMB + // instruction address. + Arm_address + destination_address() const + { return this->destination_address_; } + + // Return the instruction being fixed up. + uint32_t + original_insn() const + { return this->original_insn_; } + + protected: + // Cortex_a8_stubs are created via a stub factory. So these are protected. + Cortex_a8_stub(const Stub_template* stub_template, Relobj* relobj, + unsigned int shndx, Arm_address source_address, + Arm_address destination_address, uint32_t original_insn) + : Stub(stub_template), relobj_(relobj), shndx_(shndx), + source_address_(source_address | 1U), + destination_address_(destination_address), + original_insn_(original_insn) + { } + + friend class Stub_factory; + + // Return the relocation target address of the i-th relocation in the + // stub. + Arm_address + do_reloc_target(size_t i) + { + if (this->stub_template()->type() == arm_stub_a8_veneer_b_cond) + { + // 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_; + } + } + + // Return an instruction for the THUMB16_SPECIAL_TYPE instruction template. + uint16_t + do_thumb16_special(size_t); + + private: + // Object of the code section containing the branch being fixed up. + Relobj* relobj_; + // Section index of the code section containing the branch begin fixed up. + unsigned int shndx_; + // Source address of original branch. + Arm_address source_address_; + // Destination address of the original branch. + Arm_address destination_address_; + // Original branch instruction. This is needed for copying the condition + // code from a condition branch to its stub. + uint32_t original_insn_; +}; + +// ARMv4 BX Rx branch relocation stub class. +class Arm_v4bx_stub : public Stub +{ + public: + ~Arm_v4bx_stub() + { } + + // Return the associated register. + uint32_t + reg() const + { return this->reg_; } + + protected: + // Arm V4BX stubs are created via a stub factory. So these are protected. + Arm_v4bx_stub(const Stub_template* stub_template, const uint32_t reg) + : Stub(stub_template), reg_(reg) + { } + + friend class Stub_factory; + + // Return the relocation target address of the i-th relocation in the + // stub. + Arm_address + do_reloc_target(size_t) + { gold_unreachable(); } + + // This may be overridden in the child class. + virtual void + do_write(unsigned char* view, section_size_type view_size, bool big_endian) + { + if (big_endian) + this->do_fixed_endian_v4bx_write(view, view_size); + else + this->do_fixed_endian_v4bx_write(view, view_size); + } + + private: + // A template to implement do_write. + template + void inline + do_fixed_endian_v4bx_write(unsigned char* view, section_size_type) + { + const Insn_template* insns = this->stub_template()->insns(); + elfcpp::Swap<32, big_endian>::writeval(view, + (insns[0].data() + + (this->reg_ << 16))); + view += insns[0].size(); + elfcpp::Swap<32, big_endian>::writeval(view, + (insns[1].data() + this->reg_)); + view += insns[1].size(); + elfcpp::Swap<32, big_endian>::writeval(view, + (insns[2].data() + this->reg_)); + } + + // A register index (r0-r14), which is associated with the stub. + uint32_t reg_; +}; + +// Stub factory class. + +class Stub_factory +{ + public: + // Return the unique instance of this class. + static const Stub_factory& + get_instance() + { + static Stub_factory singleton; + return singleton; + } + + // Make a relocation stub. + Reloc_stub* + make_reloc_stub(Stub_type stub_type) const + { + gold_assert(stub_type >= arm_stub_reloc_first + && stub_type <= arm_stub_reloc_last); + return new Reloc_stub(this->stub_templates_[stub_type]); + } + + // Make a Cortex-A8 stub. + Cortex_a8_stub* + make_cortex_a8_stub(Stub_type stub_type, Relobj* relobj, unsigned int shndx, + Arm_address source, Arm_address destination, + uint32_t original_insn) const + { + gold_assert(stub_type >= arm_stub_cortex_a8_first + && stub_type <= arm_stub_cortex_a8_last); + return new Cortex_a8_stub(this->stub_templates_[stub_type], relobj, shndx, + source, destination, original_insn); + } + + // Make an ARM V4BX relocation stub. + // This method creates a stub from the arm_stub_v4_veneer_bx template only. + Arm_v4bx_stub* + make_arm_v4bx_stub(uint32_t reg) const + { + gold_assert(reg < 0xf); + return new Arm_v4bx_stub(this->stub_templates_[arm_stub_v4_veneer_bx], + reg); + } + + 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]; +}; + +// A class to hold stubs for the ARM target. + +template +class Stub_table : public Output_data +{ + public: + Stub_table(Arm_input_section* owner) + : Output_data(), owner_(owner), reloc_stubs_(), reloc_stubs_size_(0), + reloc_stubs_addralign_(1), cortex_a8_stubs_(), arm_v4bx_stubs_(0xf), + prev_data_size_(0), prev_addralign_(1) + { } + + ~Stub_table() + { } + + // Owner of this stub table. + Arm_input_section* + owner() const + { return this->owner_; } + + // Whether this stub table is empty. + bool + empty() const + { + return (this->reloc_stubs_.empty() + && this->cortex_a8_stubs_.empty() + && this->arm_v4bx_stubs_.empty()); + } + + // Return the current data size. + off_t + current_data_size() const + { return this->current_data_size_for_child(); } + + // Add a STUB using KEY. The caller is responsible for avoiding addition + // if a STUB with the same key has already been added. + void + add_reloc_stub(Reloc_stub* stub, const Reloc_stub::Key& key) + { + const Stub_template* stub_template = stub->stub_template(); + gold_assert(stub_template->type() == key.stub_type()); + this->reloc_stubs_[key] = stub; + + // Assign stub offset early. We can do this because we never remove + // reloc stubs and they are in the beginning of the stub table. + uint64_t align = stub_template->alignment(); + this->reloc_stubs_size_ = align_address(this->reloc_stubs_size_, align); + stub->set_offset(this->reloc_stubs_size_); + this->reloc_stubs_size_ += stub_template->size(); + this->reloc_stubs_addralign_ = + std::max(this->reloc_stubs_addralign_, align); + } + + // Add a Cortex-A8 STUB that fixes up a THUMB branch at ADDRESS. + // The caller is responsible for avoiding addition if a STUB with the same + // address has already been added. + void + add_cortex_a8_stub(Arm_address address, Cortex_a8_stub* stub) + { + std::pair value(address, stub); + this->cortex_a8_stubs_.insert(value); + } + + // Add an ARM V4BX relocation stub. A register index will be retrieved + // from the stub. + void + add_arm_v4bx_stub(Arm_v4bx_stub* stub) + { + gold_assert(stub != NULL && this->arm_v4bx_stubs_[stub->reg()] == NULL); + this->arm_v4bx_stubs_[stub->reg()] = stub; + } + + // Remove all Cortex-A8 stubs. + void + remove_all_cortex_a8_stubs(); + + // Look up a relocation stub using KEY. Return NULL if there is none. + Reloc_stub* + find_reloc_stub(const Reloc_stub::Key& key) const + { + typename Reloc_stub_map::const_iterator p = this->reloc_stubs_.find(key); + return (p != this->reloc_stubs_.end()) ? p->second : NULL; + } + + // Look up an arm v4bx relocation stub using the register index. + // Return NULL if there is none. + Arm_v4bx_stub* + find_arm_v4bx_stub(const uint32_t reg) const + { + gold_assert(reg < 0xf); + return this->arm_v4bx_stubs_[reg]; + } + + // Relocate stubs in this stub table. + void + relocate_stubs(const Relocate_info<32, big_endian>*, + Target_arm*, Output_section*, + unsigned char*, Arm_address, section_size_type); + + // Update data size and alignment at the end of a relaxation pass. Return + // true if either data size or alignment is different from that of the + // previous relaxation pass. + bool + update_data_size_and_addralign(); + + // Finalize stubs. Set the offsets of all stubs and mark input sections + // 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*, + unsigned char*, Arm_address, + section_size_type); + + protected: + // Write out section contents. + void + do_write(Output_file*); + + // Return the required alignment. + uint64_t + do_addralign() const + { return this->prev_addralign_; } + + // Reset address and file offset. + void + do_reset_address_and_file_offset() + { this->set_current_data_size_for_child(this->prev_data_size_); } + + // Set final data size. + void + set_final_data_size() + { this->set_data_size(this->current_data_size()); } + + private: + // Relocate one stub. + void + relocate_stub(Stub*, const Relocate_info<32, big_endian>*, + Target_arm*, Output_section*, + unsigned char*, Arm_address, section_size_type); + + // Unordered map of relocation stubs. + typedef + Unordered_map + Reloc_stub_map; + + // List of Cortex-A8 stubs ordered by addresses of branches being + // fixed up in output. + typedef std::map Cortex_a8_stub_list; + // List of Arm V4BX relocation stubs ordered by associated registers. + typedef std::vector Arm_v4bx_stub_list; + + // Owner of this stub table. + Arm_input_section* owner_; + // The relocation stubs. + Reloc_stub_map reloc_stubs_; + // Size of reloc stubs. + off_t reloc_stubs_size_; + // Maximum address alignment of reloc stubs. + uint64_t reloc_stubs_addralign_; + // The cortex_a8_stubs. + Cortex_a8_stub_list cortex_a8_stubs_; + // The Arm V4BX relocation stubs. + Arm_v4bx_stub_list arm_v4bx_stubs_; + // data size of this in the previous pass. + off_t prev_data_size_; + // address alignment of this in the previous pass. + uint64_t prev_addralign_; +}; + +// Arm_exidx_cantunwind class. This represents an EXIDX_CANTUNWIND entry +// we add to the end of an EXIDX input section that goes into the output. + +class Arm_exidx_cantunwind : public Output_section_data +{ + public: + Arm_exidx_cantunwind(Relobj* relobj, unsigned int shndx) + : Output_section_data(8, 4, true), relobj_(relobj), shndx_(shndx) + { } + + // Return the object containing the section pointed by this. + Relobj* + relobj() const + { return this->relobj_; } + + // Return the section index of the section pointed by this. + unsigned int + shndx() const + { return this->shndx_; } + + protected: + void + do_write(Output_file* of) + { + if (parameters->target().is_big_endian()) + this->do_fixed_endian_write(of); + else + this->do_fixed_endian_write(of); + } + + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _("** ARM cantunwind")); } + + private: + // Implement do_write for a given endianness. + template + 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. + unsigned int shndx_; +}; + +// 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. + +typedef std::map + Arm_exidx_section_offset_map; + +// Arm_exidx_merged_section class. This represents an EXIDX input section +// with some of its entries merged. + +class Arm_exidx_merged_section : public Output_relaxed_input_section +{ + public: + // Constructor for Arm_exidx_merged_section. + // EXIDX_INPUT_SECTION points to the unmodified EXIDX input section. + // SECTION_OFFSET_MAP points to a section offset map describing how + // parts of the input section are mapped to output. DELETED_BYTES is + // the number of bytes deleted from the EXIDX input section. + Arm_exidx_merged_section( + const Arm_exidx_input_section& exidx_input_section, + const Arm_exidx_section_offset_map& section_offset_map, + uint32_t deleted_bytes); + + // Build output contents. + void + build_contents(const unsigned char*, section_size_type); + + // Return the original EXIDX input section. + const Arm_exidx_input_section& + exidx_input_section() const + { return this->exidx_input_section_; } + + // Return the section offset map. + const Arm_exidx_section_offset_map& + section_offset_map() const + { return this->section_offset_map_; } + + protected: + // Write merged section into file OF. + void + do_write(Output_file* of); + + bool + do_output_offset(const Relobj*, unsigned int, section_offset_type, + section_offset_type*) const; + + private: + // Original EXIDX 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 + // and save it here to avoid accessing the original EXIDX section when + // we cannot lock the sections' object. + unsigned char* section_contents_; +}; + +// A class to wrap an ordinary input section containing executable code. + +template +class Arm_input_section : public Output_relaxed_input_section +{ + public: + Arm_input_section(Relobj* relobj, unsigned int shndx) + : Output_relaxed_input_section(relobj, shndx, 1), + original_addralign_(1), original_size_(0), stub_table_(NULL), + original_contents_(NULL) + { } + + ~Arm_input_section() + { delete[] this->original_contents_; } + + // Initialize. + void + init(); + + // Whether this is a stub table owner. + bool + is_stub_table_owner() const + { return this->stub_table_ != NULL && this->stub_table_->owner() == this; } + + // Return the stub table. + Stub_table* + stub_table() const + { return this->stub_table_; } + + // Set the stub_table. + void + set_stub_table(Stub_table* stub_table) + { this->stub_table_ = stub_table; } + + // Downcast a base pointer to an Arm_input_section pointer. This is + // not type-safe but we only use Arm_input_section not the base class. + static Arm_input_section* + as_arm_input_section(Output_relaxed_input_section* poris) + { return static_cast*>(poris); } + + // Return the original size of the section. + uint32_t + original_size() const + { return this->original_size_; } + + protected: + // Write data to output file. + void + do_write(Output_file*); + + // Return required alignment of this. + uint64_t + do_addralign() const + { + if (this->is_stub_table_owner()) + return std::max(this->stub_table_->addralign(), + static_cast(this->original_addralign_)); + else + return this->original_addralign_; + } + + // Finalize data size. + void + set_final_data_size(); + + // Reset address and file offset. + void + do_reset_address_and_file_offset(); + + // Output offset. + bool + do_output_offset(const Relobj* object, unsigned int shndx, + section_offset_type offset, + section_offset_type* poutput) const + { + if ((object == this->relobj()) + && (shndx == this->shndx()) + && (offset >= 0) + && (offset <= + convert_types(this->original_size_))) + { + *poutput = offset; + return true; + } + else + return false; + } + + private: + // Copying is not allowed. + Arm_input_section(const Arm_input_section&); + Arm_input_section& operator=(const Arm_input_section&); + + // Address alignment of the original input section. + uint32_t original_addralign_; + // Section size of the original input section. + uint32_t original_size_; + // Stub table. + Stub_table* stub_table_; + // Original section contents. We have to make a copy here since the file + // containing the original section may not be locked when we need to access + // the contents. + unsigned char* original_contents_; +}; + +// Arm_exidx_fixup class. This is used to define a number of methods +// and keep states for fixing up EXIDX coverage. + +class Arm_exidx_fixup +{ + public: + Arm_exidx_fixup(Output_section* exidx_output_section, + bool merge_exidx_entries = true) + : exidx_output_section_(exidx_output_section), last_unwind_type_(UT_NONE), + last_inlined_entry_(0), last_input_section_(NULL), + section_offset_map_(NULL), first_output_text_section_(NULL), + merge_exidx_entries_(merge_exidx_entries) + { } + + ~Arm_exidx_fixup() + { delete this->section_offset_map_; } + + // Process an EXIDX section for entry merging. SECTION_CONTENTS points + // to the EXIDX contents and SECTION_SIZE is the size of the contents. Return + // number of bytes to be deleted in output. If parts of the input EXIDX + // section are merged a heap allocated Arm_exidx_section_offset_map is store + // in the located PSECTION_OFFSET_MAP. The caller owns the map and is + // responsible for releasing it. + template + uint32_t + process_exidx_section(const Arm_exidx_input_section* exidx_input_section, + 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 + add_exidx_cantunwind_as_needed(); + + // Return the output section for the text section which is linked to the + // first exidx input in output. + Output_section* + first_output_text_section() const + { return this->first_output_text_section_; } + + private: + // Copying is not allowed. + Arm_exidx_fixup(const Arm_exidx_fixup&); + Arm_exidx_fixup& operator=(const Arm_exidx_fixup&); + + // Type of EXIDX unwind entry. + enum Unwind_type + { + // No type. + UT_NONE, + // EXIDX_CANTUNWIND. + UT_EXIDX_CANTUNWIND, + // Inlined entry. + UT_INLINED_ENTRY, + // Normal entry. + UT_NORMAL_ENTRY, + }; + + // Process an EXIDX entry. We only care about the second word of the + // entry. Return true if the entry can be deleted. + bool + process_exidx_entry(uint32_t second_word); + + // Update the current section offset map during EXIDX section fix-up. + // If there is no map, create one. INPUT_OFFSET is the offset of a + // reference point, DELETED_BYTES is the number of deleted by in the + // section so far. If DELETE_ENTRY is true, the reference point and + // all offsets after the previous reference point are discarded. + void + update_offset_map(section_offset_type input_offset, + section_size_type deleted_bytes, bool delete_entry); + + // EXIDX output section. + Output_section* exidx_output_section_; + // Unwind type of the last EXIDX entry processed. + Unwind_type last_unwind_type_; + // Last seen inlined EXIDX entry. + uint32_t last_inlined_entry_; + // Last processed EXIDX input section. + const Arm_exidx_input_section* last_input_section_; + // Section offset map created in process_exidx_section. + Arm_exidx_section_offset_map* section_offset_map_; + // Output section for the text section which is linked to the first exidx + // input in output. + Output_section* first_output_text_section_; + + bool merge_exidx_entries_; +}; + +// Arm output section class. This is defined mainly to add a number of +// stub generation methods. + +template +class Arm_output_section : public Output_section +{ + public: + typedef std::vector > Text_section_list; + + // We need to force SHF_LINK_ORDER in a SHT_ARM_EXIDX section. + Arm_output_section(const char* name, elfcpp::Elf_Word type, + elfcpp::Elf_Xword flags) + : Output_section(name, type, + (type == elfcpp::SHT_ARM_EXIDX + ? flags | elfcpp::SHF_LINK_ORDER + : flags)) + { + if (type == elfcpp::SHT_ARM_EXIDX) + this->set_always_keeps_input_sections(); + } + + ~Arm_output_section() + { } + + // Group input sections for stub generation. + void + group_sections(section_size_type, bool, Target_arm*, const Task*); + + // Downcast a base pointer to an Arm_output_section pointer. This is + // not type-safe but we only use Arm_output_section not the base class. + static Arm_output_section* + as_arm_output_section(Output_section* os) + { return static_cast*>(os); } + + // Append all input text sections in this into LIST. + void + append_text_sections_to_list(Text_section_list* list); + + // Fix EXIDX coverage of this EXIDX output section. SORTED_TEXT_SECTION + // is a list of text input sections sorted in ascending order of their + // output addresses. + void + fix_exidx_coverage(Layout* layout, + const Text_section_list& sorted_text_section, + Symbol_table* symtab, + bool merge_exidx_entries, + const Task* task); + + // Link an EXIDX section into its corresponding text section. + void + set_exidx_section_link(); + + private: + // For convenience. + typedef Output_section::Input_section Input_section; + typedef Output_section::Input_section_list Input_section_list; + + // Create a stub group. + void create_stub_group(Input_section_list::const_iterator, + Input_section_list::const_iterator, + Input_section_list::const_iterator, + Target_arm*, + std::vector*, + const Task* task); +}; + +// Arm_exidx_input_section class. This represents an EXIDX input section. + +class Arm_exidx_input_section +{ + public: + static const section_offset_type invalid_offset = + static_cast(-1); + + Arm_exidx_input_section(Relobj* relobj, unsigned int shndx, + unsigned int link, uint32_t size, + uint32_t addralign, uint32_t text_size) + : relobj_(relobj), shndx_(shndx), link_(link), size_(size), + addralign_(addralign), text_size_(text_size), has_errors_(false) + { } + + ~Arm_exidx_input_section() + { } + + // Accessors: This is a read-only class. + + // Return the object containing this EXIDX input section. + Relobj* + relobj() const + { return this->relobj_; } + + // Return the section index of this EXIDX input section. + unsigned int + shndx() const + { return this->shndx_; } + + // Return the section index of linked text section in the same object. + unsigned int + link() const + { return this->link_; } + + // Return size of the EXIDX input section. + uint32_t + size() const + { return this->size_; } + + // Return address alignment of EXIDX input section. + uint32_t + addralign() const + { return this->addralign_; } + + // Return size of the associated text input section. + uint32_t + text_size() const + { return this->text_size_; } + + // Whether there are any errors in the EXIDX input section. + bool + has_errors() const + { return this->has_errors_; } + + // Set has-errors flag. + void + set_has_errors() + { this->has_errors_ = true; } + + private: + // Object containing this. + Relobj* relobj_; + // Section index of this. + unsigned int shndx_; + // text section linked to this in the same object. + unsigned int link_; + // Size of this. For ARM 32-bit is sufficient. + uint32_t size_; + // Address alignment of this. For ARM 32-bit is sufficient. + uint32_t addralign_; + // Size of associated text section. + uint32_t text_size_; + // Whether this has any errors. + bool has_errors_; +}; + +// Arm_relobj class. + +template +class Arm_relobj : public Sized_relobj_file<32, big_endian> +{ + public: + static const Arm_address invalid_address = static_cast(-1); + + Arm_relobj(const std::string& name, Input_file* input_file, off_t offset, + 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_(), + section_has_cortex_a8_workaround_(NULL), exidx_section_map_(), + output_local_symbol_count_needs_update_(false), + merge_flags_and_attributes_(true) + { } + + ~Arm_relobj() + { delete this->attributes_section_data_; } + + // Return the stub table of the SHNDX-th section if there is one. + Stub_table* + stub_table(unsigned int shndx) const + { + gold_assert(shndx < this->stub_tables_.size()); + return this->stub_tables_[shndx]; + } + + // Set STUB_TABLE to be the stub_table of the SHNDX-th section. + void + set_stub_table(unsigned int shndx, Stub_table* stub_table) + { + gold_assert(shndx < this->stub_tables_.size()); + this->stub_tables_[shndx] = stub_table; + } + + // Whether a local symbol is a THUMB function. R_SYM is the symbol table + // index. This is only valid after do_count_local_symbol is called. + bool + local_symbol_is_thumb_function(unsigned int r_sym) const + { + gold_assert(r_sym < this->local_symbol_is_thumb_function_.size()); + return this->local_symbol_is_thumb_function_[r_sym]; + } + + // Scan all relocation sections for stub generation. + void + scan_sections_for_stubs(Target_arm*, const Symbol_table*, + const Layout*); + + // Convert regular input section with index SHNDX to a relaxed section. + void + convert_input_section_to_relaxed_section(unsigned shndx) + { + // The stubs have relocations and we need to process them after writing + // out the stubs. So relocation now must follow section write. + this->set_section_offset(shndx, -1ULL); + this->set_relocs_must_follow_section_writes(); + } + + // Downcast a base pointer to an Arm_relobj pointer. This is + // not type-safe but we only use Arm_relobj not the base class. + static Arm_relobj* + as_arm_relobj(Relobj* relobj) + { return static_cast*>(relobj); } + + // Processor-specific flags in ELF file header. This is valid only after + // reading symbols. + elfcpp::Elf_Word + processor_specific_flags() const + { return this->processor_specific_flags_; } + + // Attribute section data This is the contents of the .ARM.attribute section + // if there is one. + const Attributes_section_data* + attributes_section_data() const + { return this->attributes_section_data_; } + + // Mapping symbol location. + typedef std::pair Mapping_symbol_position; + + // Functor for STL container. + struct Mapping_symbol_position_less + { + bool + operator()(const Mapping_symbol_position& p1, + const Mapping_symbol_position& p2) const + { + return (p1.first < p2.first + || (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_symbols_info; + + // 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) + { + if (this->section_has_cortex_a8_workaround_ == NULL) + this->section_has_cortex_a8_workaround_ = + new std::vector(this->shnum(), false); + (*this->section_has_cortex_a8_workaround_)[shndx] = true; + } + + // Return the EXIDX section of an text section with index SHNDX or NULL + // if the text section has no associated EXIDX section. + const Arm_exidx_input_section* + exidx_input_section_by_link(unsigned int shndx) const + { + Exidx_section_map::const_iterator p = this->exidx_section_map_.find(shndx); + return ((p != this->exidx_section_map_.end() + && p->second->link() == shndx) + ? p->second + : NULL); + } + + // Return the EXIDX section with index SHNDX or NULL if there is none. + const Arm_exidx_input_section* + exidx_input_section_by_shndx(unsigned shndx) const + { + Exidx_section_map::const_iterator p = this->exidx_section_map_.find(shndx); + return ((p != this->exidx_section_map_.end() + && p->second->shndx() == shndx) + ? p->second + : NULL); + } + + // Whether output local symbol count needs updating. + bool + output_local_symbol_count_needs_update() const + { return this->output_local_symbol_count_needs_update_; } + + // Set output_local_symbol_count_needs_update flag to be true. + 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(); + + // Whether we want to merge processor-specific flags and attributes. + 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* list) const + { + list->clear(); + for (Exidx_section_map::const_iterator p = this->exidx_section_map_.begin(); + p != this->exidx_section_map_.end(); + ++p) + { + if (p->second->shndx() == p->first) + list->push_back(p->first); + } + // Sort list to make result independent of implementation of map. + std::sort(list->begin(), list->end()); + } + + protected: + // Post constructor setup. + void + do_setup() + { + // Call parent's setup method. + Sized_relobj_file<32, big_endian>::do_setup(); + + // Initialize look-up tables. + Stub_table_list empty_stub_table_list(this->shnum(), NULL); + this->stub_tables_.swap(empty_stub_table_list); + } + + // Count the local symbols. + void + do_count_local_symbols(Stringpool_template*, + Stringpool_template*); + + void + do_relocate_sections( + const Symbol_table* symtab, const Layout* layout, + const unsigned char* pshdrs, Output_file* of, + typename Sized_relobj_file<32, big_endian>::Views* pivews); + + // Read the symbol information. + void + do_read_symbols(Read_symbols_data* sd); + + // Process relocs for garbage collection. + void + do_gc_process_relocs(Symbol_table*, Layout*, Read_relocs_data*); + + private: + + // Whether a section needs to be scanned for relocation stubs. + bool + section_needs_reloc_stub_scanning(const elfcpp::Shdr<32, big_endian>&, + const Relobj::Output_sections&, + const Symbol_table*, const unsigned char*); + + // Whether a section is a scannable text section. + bool + section_is_scannable(const elfcpp::Shdr<32, big_endian>&, unsigned int, + const Output_section*, const Symbol_table*); + + // Whether a section needs to be scanned for the Cortex-A8 erratum. + bool + section_needs_cortex_a8_stub_scanning(const elfcpp::Shdr<32, big_endian>&, + unsigned int, Output_section*, + const Symbol_table*); + + // Scan a section for the Cortex-A8 erratum. + void + scan_section_for_cortex_a8_erratum(const elfcpp::Shdr<32, big_endian>&, + unsigned int, Output_section*, + Target_arm*); + + // Find the linked text section of an EXIDX section by looking at the + // first relocation of the EXIDX section. PSHDR points to the section + // headers of a relocation section and PSYMS points to the local symbols. + // PSHNDX points to a location storing the text section index if found. + // Return whether we can find the linked section. + bool + find_linked_text_section(const unsigned char* pshdr, + const unsigned char* psyms, unsigned int* pshndx); + + // + // Make a new Arm_exidx_input_section object for EXIDX section with + // index SHNDX and section header SHDR. TEXT_SHNDX is the section + // index of the linked text section. + void + make_exidx_input_section(unsigned int shndx, + const elfcpp::Shdr<32, big_endian>& shdr, + unsigned int text_shndx, + const elfcpp::Shdr<32, big_endian>& text_shdr); + + // Return the output address of either a plain input section or a + // relaxed input section. SHNDX is the section index. + Arm_address + simple_input_section_output_address(unsigned int, Output_section*); + + typedef std::vector*> Stub_table_list; + typedef Unordered_map + Exidx_section_map; + + // List of stub tables. + Stub_table_list stub_tables_; + // Bit vector to tell if a local symbol is a thumb function or not. + // This is only valid after do_count_local_symbol is called. + std::vector local_symbol_is_thumb_function_; + // processor-specific flags in ELF file header. + elfcpp::Elf_Word processor_specific_flags_; + // Object attributes if there is an .ARM.attributes section or NULL. + Attributes_section_data* attributes_section_data_; + // Mapping symbols information. + Mapping_symbols_info mapping_symbols_info_; + // Bitmap to indicate sections with Cortex-A8 workaround or NULL. + std::vector* section_has_cortex_a8_workaround_; + // Map a text section to its associated .ARM.exidx section, if there is one. + Exidx_section_map exidx_section_map_; + // Whether output local symbol count needs updating. + bool output_local_symbol_count_needs_update_; + // Whether we merge processor flags and attributes of this object to + // output. + bool merge_flags_and_attributes_; +}; + +// Arm_dynobj class. + +template +class Arm_dynobj : public Sized_dynobj<32, big_endian> +{ + public: + Arm_dynobj(const std::string& name, Input_file* input_file, off_t offset, + const elfcpp::Ehdr<32, big_endian>& ehdr) + : 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_; } + + // Downcast a base pointer to an Arm_relobj pointer. This is + // not type-safe but we only use Arm_relobj not the base class. + static Arm_dynobj* + as_arm_dynobj(Dynobj* dynobj) + { return static_cast*>(dynobj); } + + // Processor-specific flags in ELF file header. This is valid only after + // reading symbols. + elfcpp::Elf_Word + processor_specific_flags() const + { return this->processor_specific_flags_; } + + // Attributes section data. + const Attributes_section_data* + attributes_section_data() const + { return this->attributes_section_data_; } + + protected: + // Read the symbol information. + void + do_read_symbols(Read_symbols_data* sd); + + private: + // processor-specific flags in ELF file header. + elfcpp::Elf_Word processor_specific_flags_; + // Object attributes if there is an .ARM.attributes section or NULL. + Attributes_section_data* attributes_section_data_; +}; + +// Functor to read reloc addends during stub generation. + +template +struct Stub_addend_reader +{ + // Return the addend for a relocation of a particular type. Depending + // on whether this is a REL or RELA relocation, read the addend from a + // view or from a Reloc object. + elfcpp::Elf_types<32>::Elf_Swxword + operator()( + unsigned int /* r_type */, + const unsigned char* /* view */, + const typename Reloc_types::Reloc& /* reloc */) const; +}; + +// Specialized Stub_addend_reader for SHT_REL type relocation sections. + +template +struct Stub_addend_reader +{ + elfcpp::Elf_types<32>::Elf_Swxword + operator()( + unsigned int, + const unsigned char*, + const typename Reloc_types::Reloc&) const; +}; + +// Specialized Stub_addend_reader for RELA type relocation sections. +// We currently do not handle RELA type relocation sections but it is trivial +// to implement the addend reader. This is provided for completeness and to +// make it easier to add support for RELA relocation sections in the future. + +template +struct Stub_addend_reader +{ + elfcpp::Elf_types<32>::Elf_Swxword + operator()( + unsigned int, + const unsigned char*, + const typename Reloc_types::Reloc& reloc) const + { return reloc.get_r_addend(); } +}; + +// Cortex_a8_reloc class. We keep record of relocation that may need +// the Cortex-A8 erratum workaround. + +class Cortex_a8_reloc +{ + public: + Cortex_a8_reloc(Reloc_stub* reloc_stub, unsigned r_type, + Arm_address destination) + : reloc_stub_(reloc_stub), r_type_(r_type), destination_(destination) + { } + + ~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 the relocation type. + unsigned int + r_type() const + { return this->r_type_; } + + // Return the destination address of the relocation. LSB stores the THUMB + // bit. + Arm_address + destination() const + { return this->destination_; } + + private: + // Associated relocation stub if there is one, or NULL. + const Reloc_stub* reloc_stub_; + // Relocation type. + unsigned int r_type_; + // Destination address of this relocation. LSB is used to distinguish + // ARM/THUMB mode. + Arm_address destination_; +}; + +// Arm_output_data_got class. We derive this from Output_data_got to add +// extra methods to handle TLS relocations in a static link. + +template +class Arm_output_data_got : public Output_data_got<32, big_endian> +{ + public: + Arm_output_data_got(Symbol_table* symtab, Layout* layout) + : Output_data_got<32, big_endian>(), symbol_table_(symtab), layout_(layout) + { } + + // Add a static entry for the GOT entry at OFFSET. GSYM is a global + // symbol and R_TYPE is the code of a dynamic relocation that needs to be + // applied in a static link. + void + add_static_reloc(unsigned int got_offset, unsigned int r_type, Symbol* gsym) + { this->static_relocs_.push_back(Static_reloc(got_offset, r_type, gsym)); } + + // Add a static reloc for the GOT entry at OFFSET. RELOBJ is an object + // defining a local symbol with INDEX. R_TYPE is the code of a dynamic + // relocation that needs to be applied in a static link. + void + add_static_reloc(unsigned int got_offset, unsigned int r_type, + Sized_relobj_file<32, big_endian>* relobj, + unsigned int index) + { + this->static_relocs_.push_back(Static_reloc(got_offset, r_type, relobj, + index)); + } + + // Add a GOT pair for R_ARM_TLS_GD32. The creates a pair of GOT entries. + // The first one is initialized to be 1, which is the module index for + // the main executable and the second one 0. A reloc of the type + // R_ARM_TLS_DTPOFF32 will be created for the second GOT entry and will + // be applied by gold. GSYM is a global symbol. + void + add_tls_gd32_with_static_reloc(unsigned int got_type, Symbol* gsym); + + // Same as the above but for a local symbol in OBJECT with INDEX. + void + add_tls_gd32_with_static_reloc(unsigned int got_type, + Sized_relobj_file<32, big_endian>* object, + unsigned int index); + + protected: + // Write out the GOT table. + void + do_write(Output_file*); + + private: + // This class represent dynamic relocations that need to be applied by + // gold because we are using TLS relocations in a static link. + class Static_reloc + { + public: + Static_reloc(unsigned int got_offset, unsigned int r_type, Symbol* gsym) + : got_offset_(got_offset), r_type_(r_type), symbol_is_global_(true) + { this->u_.global.symbol = gsym; } + + Static_reloc(unsigned int got_offset, unsigned int r_type, + Sized_relobj_file<32, big_endian>* relobj, unsigned int index) + : got_offset_(got_offset), r_type_(r_type), symbol_is_global_(false) + { + this->u_.local.relobj = relobj; + this->u_.local.index = index; + } + + // Return the GOT offset. + unsigned int + got_offset() const + { return this->got_offset_; } + + // Relocation type. + unsigned int + r_type() const + { return this->r_type_; } + + // Whether the symbol is global or not. + bool + symbol_is_global() const + { return this->symbol_is_global_; } + + // For a relocation against a global symbol, the global symbol. + Symbol* + symbol() const + { + gold_assert(this->symbol_is_global_); + return this->u_.global.symbol; + } + + // For a relocation against a local symbol, the defining object. + Sized_relobj_file<32, big_endian>* + relobj() const + { + gold_assert(!this->symbol_is_global_); + return this->u_.local.relobj; + } + + // For a relocation against a local symbol, the local symbol index. + unsigned int + index() const + { + gold_assert(!this->symbol_is_global_); + return this->u_.local.index; + } + + private: + // GOT offset of the entry to which this relocation is applied. + unsigned int got_offset_; + // Type of relocation. + unsigned int r_type_; + // Whether this relocation is against a global symbol. + bool symbol_is_global_; + // A global or local symbol. + union + { + struct + { + // For a global symbol, the symbol itself. + Symbol* symbol; + } global; + struct + { + // For a local symbol, the object defining object. + Sized_relobj_file<32, big_endian>* relobj; + // For a local symbol, the symbol index. + unsigned int index; + } local; + } u_; + }; + + // Symbol table of the output object. + Symbol_table* symbol_table_; + // Layout of the output object. + Layout* layout_; + // Static relocs to be applied to the GOT. + std::vector static_relocs_; +}; + +// The ARM target has many relocation types with odd-sizes or noncontiguous +// bits. The default handling of relocatable relocation cannot process these +// relocations. So we have to extend the default code. + +template +class Arm_scan_relocatable_relocs : + public Default_scan_relocatable_relocs +{ + public: + // Return the strategy to use for a local symbol which is a section + // symbol, given the relocation type. + inline Relocatable_relocs::Reloc_strategy + local_section_strategy(unsigned int r_type, Relobj*) + { + if (sh_type == elfcpp::SHT_RELA) + return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_RELA; + else + { + if (r_type == elfcpp::R_ARM_TARGET1 + || r_type == elfcpp::R_ARM_TARGET2) + { + const Target_arm* arm_target = + Target_arm::default_target(); + r_type = arm_target->get_real_reloc_type(r_type); + } + + switch(r_type) + { + // Relocations that write nothing. These exclude R_ARM_TARGET1 + // and R_ARM_TARGET2. + case elfcpp::R_ARM_NONE: + case elfcpp::R_ARM_V4BX: + case elfcpp::R_ARM_TLS_GOTDESC: + case elfcpp::R_ARM_TLS_CALL: + case elfcpp::R_ARM_TLS_DESCSEQ: + case elfcpp::R_ARM_THM_TLS_CALL: + case elfcpp::R_ARM_GOTRELAX: + case elfcpp::R_ARM_GNU_VTENTRY: + case elfcpp::R_ARM_GNU_VTINHERIT: + case elfcpp::R_ARM_THM_TLS_DESCSEQ16: + case elfcpp::R_ARM_THM_TLS_DESCSEQ32: + return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_0; + // These should have been converted to something else above. + case elfcpp::R_ARM_TARGET1: + case elfcpp::R_ARM_TARGET2: + gold_unreachable(); + // Relocations that write full 32 bits and + // have alignment of 1. + case elfcpp::R_ARM_ABS32: + case elfcpp::R_ARM_REL32: + case elfcpp::R_ARM_SBREL32: + case elfcpp::R_ARM_GOTOFF32: + case elfcpp::R_ARM_BASE_PREL: + case elfcpp::R_ARM_GOT_BREL: + case elfcpp::R_ARM_BASE_ABS: + case elfcpp::R_ARM_ABS32_NOI: + case elfcpp::R_ARM_REL32_NOI: + case elfcpp::R_ARM_PLT32_ABS: + case elfcpp::R_ARM_GOT_ABS: + case elfcpp::R_ARM_GOT_PREL: + case elfcpp::R_ARM_TLS_GD32: + case elfcpp::R_ARM_TLS_LDM32: + case elfcpp::R_ARM_TLS_LDO32: + case elfcpp::R_ARM_TLS_IE32: + case elfcpp::R_ARM_TLS_LE32: + return Relocatable_relocs::RELOC_ADJUST_FOR_SECTION_4_UNALIGNED; + default: + // For all other static relocations, return RELOC_SPECIAL. + return Relocatable_relocs::RELOC_SPECIAL; + } + } + } +}; + +template +class Target_arm : public Sized_target<32, big_endian> +{ + public: + typedef Output_data_reloc + Reloc_section; + + // When were are relocating a stub, we pass this as the relocation number. + static const size_t fake_relnum_for_stubs = static_cast(-1); + + 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), + got_mod_index_offset_(-1U), tls_base_symbol_defined_(false), + stub_tables_(), stub_factory_(Stub_factory::get_instance()), + should_force_pic_veneer_(false), + arm_input_section_map_(), attributes_section_data_(NULL), + fix_cortex_a8_(false), cortex_a8_relocs_info_() + { } + + // Whether we force PCI branch veneers. + bool + should_force_pic_veneer() const + { return this->should_force_pic_veneer_; } + + // Set PIC veneer flag. + void + set_should_force_pic_veneer(bool value) + { this->should_force_pic_veneer_ = value; } + + // Whether we use THUMB-2 instructions. + bool + using_thumb2() const + { + Object_attribute* attr = + this->get_aeabi_object_attribute(elfcpp::Tag_CPU_arch); + int arch = attr->int_value(); + return arch == elfcpp::TAG_CPU_ARCH_V6T2 || arch >= elfcpp::TAG_CPU_ARCH_V7; + } + + // Whether we use THUMB/THUMB-2 instructions only. + bool + using_thumb_only() const + { + Object_attribute* attr = + this->get_aeabi_object_attribute(elfcpp::Tag_CPU_arch); + + if (attr->int_value() == elfcpp::TAG_CPU_ARCH_V6_M + || attr->int_value() == elfcpp::TAG_CPU_ARCH_V6S_M) + return true; + if (attr->int_value() != elfcpp::TAG_CPU_ARCH_V7 + && attr->int_value() != elfcpp::TAG_CPU_ARCH_V7E_M) + return false; + attr = this->get_aeabi_object_attribute(elfcpp::Tag_CPU_arch_profile); + return attr->int_value() == 'M'; + } + + // Whether we have an NOP instruction. If not, use mov r0, r0 instead. + bool + may_use_arm_nop() const + { + Object_attribute* attr = + this->get_aeabi_object_attribute(elfcpp::Tag_CPU_arch); + int arch = attr->int_value(); + return (arch == elfcpp::TAG_CPU_ARCH_V6T2 + || arch == elfcpp::TAG_CPU_ARCH_V6K + || arch == elfcpp::TAG_CPU_ARCH_V7 + || arch == elfcpp::TAG_CPU_ARCH_V7E_M); + } + + // Whether we have THUMB-2 NOP.W instruction. + bool + may_use_thumb2_nop() const + { + Object_attribute* attr = + this->get_aeabi_object_attribute(elfcpp::Tag_CPU_arch); + int arch = attr->int_value(); + return (arch == elfcpp::TAG_CPU_ARCH_V6T2 + || arch == elfcpp::TAG_CPU_ARCH_V7 + || arch == elfcpp::TAG_CPU_ARCH_V7E_M); + } + + // Whether we have v4T interworking instructions available. + bool + may_use_v4t_interworking() const + { + Object_attribute* attr = + this->get_aeabi_object_attribute(elfcpp::Tag_CPU_arch); + int arch = attr->int_value(); + 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 + { + Object_attribute* attr = + this->get_aeabi_object_attribute(elfcpp::Tag_CPU_arch); + int arch = attr->int_value(); + if (parameters->options().fix_arm1176()) + return (arch == elfcpp::TAG_CPU_ARCH_V6T2 + || arch == elfcpp::TAG_CPU_ARCH_V7 + || arch == elfcpp::TAG_CPU_ARCH_V6_M + || arch == elfcpp::TAG_CPU_ARCH_V6S_M + || arch == elfcpp::TAG_CPU_ARCH_V7E_M); + else + return (arch != elfcpp::TAG_CPU_ARCH_PRE_V4 + && arch != elfcpp::TAG_CPU_ARCH_V4 + && arch != elfcpp::TAG_CPU_ARCH_V4T); + } + + // Process the relocations to determine unreferenced sections for + // garbage collection. + void + gc_process_relocs(Symbol_table* symtab, + Layout* layout, + Sized_relobj_file<32, 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 + scan_relocs(Symbol_table* symtab, + Layout* layout, + Sized_relobj_file<32, 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); + + // Finalize the sections. + void + do_finalize_sections(Layout*, const Input_objects*, Symbol_table*); + + // Return the value to use for a dynamic symbol which requires special + // treatment. + uint64_t + do_dynsym_value(const Symbol*) const; + + // Relocate a section. + void + relocate_section(const Relocate_info<32, big_endian>*, + unsigned int sh_type, + const unsigned char* prelocs, + size_t reloc_count, + Output_section* output_section, + bool needs_special_offset_handling, + unsigned char* view, + Arm_address view_address, + section_size_type view_size, + const Reloc_symbol_changes*); + + // Scan the relocs during a relocatable link. + void + scan_relocatable_relocs(Symbol_table* symtab, + Layout* layout, + Sized_relobj_file<32, 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, + Relocatable_relocs*); + + // Emit relocations for a section. + void + relocate_relocs(const Relocate_info<32, big_endian>*, + unsigned int sh_type, + const unsigned char* prelocs, + size_t reloc_count, + Output_section* output_section, + typename elfcpp::Elf_types<32>::Elf_Off + offset_in_output_section, + const Relocatable_relocs*, + unsigned char* view, + Arm_address view_address, + section_size_type view_size, + unsigned char* reloc_view, + section_size_type reloc_view_size); + + // Perform target-specific processing in a relocatable link. This is + // only used if we use the relocation strategy RELOC_SPECIAL. + void + relocate_special_relocatable(const Relocate_info<32, big_endian>* relinfo, + unsigned int sh_type, + const unsigned char* preloc_in, + size_t relnum, + Output_section* output_section, + typename elfcpp::Elf_types<32>::Elf_Off + offset_in_output_section, + unsigned char* view, + typename elfcpp::Elf_types<32>::Elf_Addr + 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 + { return strcmp(sym->name(), "__tls_get_addr") == 0; } + + // Return whether there is a GOT section. + bool + has_got_section() const + { return this->got_ != NULL; } + + // Return the size of the GOT section. + section_size_type + got_size() const + { + gold_assert(this->got_ != NULL); + return this->got_->data_size(); + } + + // Return the number of entries in the GOT. + unsigned int + got_entry_count() const + { + if (!this->has_got_section()) + return 0; + return this->got_size() / 4; + } + + // Return the number of entries in the PLT. + unsigned int + plt_entry_count() const; + + // Return the offset of the first non-reserved PLT entry. + unsigned int + first_plt_entry_offset() const; + + // Return the size of each PLT entry. + unsigned int + plt_entry_size() const; + + // Map platform-specific reloc types + static unsigned int + get_real_reloc_type(unsigned int r_type); + + // + // Methods to support stub-generations. + // + + // Return the stub factory + const Stub_factory& + stub_factory() const + { return this->stub_factory_; } + + // Make a new Arm_input_section object. + Arm_input_section* + new_arm_input_section(Relobj*, unsigned int); + + // Find the Arm_input_section object corresponding to the SHNDX-th input + // section of RELOBJ. + Arm_input_section* + find_arm_input_section(Relobj* relobj, unsigned int shndx) const; + + // Make a new Stub_table + Stub_table* + new_stub_table(Arm_input_section*); + + // Scan a section for stub generation. + void + scan_section_for_stubs(const Relocate_info<32, big_endian>*, unsigned int, + const unsigned char*, size_t, Output_section*, + bool, const unsigned char*, Arm_address, + section_size_type); + + // 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* + default_target() + { + gold_assert(parameters->target().machine_code() == elfcpp::EM_ARM + && parameters->target().is_big_endian() == big_endian); + return static_cast*>( + parameters->sized_target<32, big_endian>()); + } + + // Whether NAME belongs to a mapping symbol. + static bool + is_mapping_symbol_name(const char* name) + { + return (name + && name[0] == '$' + && (name[1] == 'a' || name[1] == 't' || name[1] == 'd') + && (name[2] == '\0' || name[2] == '.')); + } + + // Whether we work around the Cortex-A8 erratum. + bool + fix_cortex_a8() const + { return this->fix_cortex_a8_; } + + // Whether we merge exidx entries in debuginfo. + bool + merge_exidx_entries() const + { return parameters->options().merge_exidx_entries(); } + + // Whether we fix R_ARM_V4BX relocation. + // 0 - do not fix + // 1 - replace with MOV instruction (armv4 target) + // 2 - make interworking veneer (>= armv4t targets only) + General_options::Fix_v4bx + fix_v4bx() const + { return parameters->options().fix_v4bx(); } + + // Scan a span of THUMB code section for Cortex-A8 erratum. + void + scan_span_for_cortex_a8_erratum(Arm_relobj*, unsigned int, + section_size_type, section_size_type, + const unsigned char*, Arm_address); + + // Apply Cortex-A8 workaround to a branch. + void + apply_cortex_a8_workaround(const Cortex_a8_stub*, Arm_address, + unsigned char*, Arm_address); + + protected: + // Make the PLT-generator object. + Output_data_plt_arm* + 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, + const elfcpp::Ehdr<32, big_endian>& ehdr); + + Object* + do_make_elf_object(const std::string&, Input_file*, off_t, + const elfcpp::Ehdr<32, !big_endian>&) + { gold_unreachable(); } + + Object* + do_make_elf_object(const std::string&, Input_file*, off_t, + const elfcpp::Ehdr<64, false>&) + { gold_unreachable(); } + + Object* + do_make_elf_object(const std::string&, Input_file*, off_t, + const elfcpp::Ehdr<64, true>&) + { gold_unreachable(); } + + // Make an output section. + Output_section* + do_make_output_section(const char* name, elfcpp::Elf_Word type, + elfcpp::Elf_Xword flags) + { return new Arm_output_section(name, type, flags); } + + void + do_adjust_elf_header(unsigned char* view, int len); + + // We only need to generate stubs, and hence perform relaxation if we are + // not doing relocatable linking. + bool + do_may_relax() const + { return !parameters->options().relocatable(); } + + bool + do_relax(int, const Input_objects*, Symbol_table*, Layout*, const Task*); + + // Determine whether an object attribute tag takes an integer, a + // string or both. + int + do_attribute_arg_type(int tag) const; + + // Reorder tags during output. + int + do_attributes_order(int num) const; + + // This is called when the target is selected as the default. + void + do_select_as_default_target() + { + // No locking is required since there should only be one default target. + // We cannot have both the big-endian and little-endian ARM targets + // as the default. + gold_assert(arm_reloc_property_table == NULL); + arm_reloc_property_table = new Arm_reloc_property_table(); + } + + // Virtual function which is set to return true by a target if + // it can use relocation types to determine if a function's + // pointer is taken. + virtual bool + do_can_check_for_function_pointers() const + { return true; } + + // Whether a section called SECTION_NAME may have function pointers to + // sections not eligible for safe ICF folding. + virtual bool + do_section_may_have_icf_unsafe_pointers(const char* section_name) const + { + return (!is_prefix_of(".ARM.exidx", section_name) + && !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* + do_make_data_plt(Layout* layout, Output_data_space* got_plt) + { + return new Output_data_plt_arm_standard(layout, got_plt); + } + + private: + // The class which scans relocations. + class Scan + { + public: + Scan() + : issued_non_pic_error_(false) + { } + + static inline int + get_reference_flags(unsigned int r_type); + + inline void + local(Symbol_table* symtab, Layout* layout, Target_arm* target, + Sized_relobj_file<32, big_endian>* object, + unsigned int data_shndx, + Output_section* output_section, + const elfcpp::Rel<32, big_endian>& reloc, unsigned int r_type, + const elfcpp::Sym<32, big_endian>& lsym, + bool is_discarded); + + inline void + global(Symbol_table* symtab, Layout* layout, Target_arm* target, + Sized_relobj_file<32, big_endian>* object, + unsigned int data_shndx, + Output_section* output_section, + const elfcpp::Rel<32, big_endian>& reloc, unsigned int r_type, + Symbol* gsym); + + 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>& , + unsigned int , + 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>& , + unsigned int , Symbol*); + + private: + static void + unsupported_reloc_local(Sized_relobj_file<32, big_endian>*, + unsigned int r_type); + + static void + unsupported_reloc_global(Sized_relobj_file<32, big_endian>*, + unsigned int r_type, Symbol*); + + void + check_non_pic(Relobj*, unsigned int r_type); + + // Almost identical to Symbol::needs_plt_entry except that it also + // handles STT_ARM_TFUNC. + static bool + symbol_needs_plt_entry(const Symbol* sym) + { + // An undefined symbol from an executable does not need a PLT entry. + if (sym->is_undefined() && !parameters->options().shared()) + return false; + + return (!parameters->doing_static_link() + && (sym->type() == elfcpp::STT_FUNC + || sym->type() == elfcpp::STT_ARM_TFUNC) + && (sym->is_from_dynobj() + || sym->is_undefined() + || sym->is_preemptible())); + } + + inline bool + possible_function_pointer_reloc(unsigned int r_type); + + // Whether we have issued an error about a non-PIC compilation. + bool issued_non_pic_error_; + }; + + // The class which implements relocation. + class Relocate + { + public: + Relocate() + { } + + ~Relocate() + { } + + // 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, + Output_section* output_section); + + // Do a relocation. Return false if the caller should not issue + // any warnings about this relocation. + inline bool + relocate(const Relocate_info<32, big_endian>*, Target_arm*, + Output_section*, size_t relnum, + const elfcpp::Rel<32, big_endian>&, + unsigned int r_type, const Sized_symbol<32>*, + const Symbol_value<32>*, + unsigned char*, Arm_address, + section_size_type); + + // Return whether we want to pass flag NON_PIC_REF for this + // reloc. This means the relocation type accesses a symbol not via + // GOT or PLT. + static inline bool + reloc_is_non_pic(unsigned int r_type) + { + switch (r_type) + { + // These relocation types reference GOT or PLT entries explicitly. + case elfcpp::R_ARM_GOT_BREL: + case elfcpp::R_ARM_GOT_ABS: + case elfcpp::R_ARM_GOT_PREL: + case elfcpp::R_ARM_GOT_BREL12: + case elfcpp::R_ARM_PLT32_ABS: + case elfcpp::R_ARM_TLS_GD32: + case elfcpp::R_ARM_TLS_LDM32: + case elfcpp::R_ARM_TLS_IE32: + case elfcpp::R_ARM_TLS_IE12GP: + + // These relocate types may use PLT entries. + case elfcpp::R_ARM_CALL: + case elfcpp::R_ARM_THM_CALL: + case elfcpp::R_ARM_JUMP24: + case elfcpp::R_ARM_THM_JUMP24: + case elfcpp::R_ARM_THM_JUMP19: + case elfcpp::R_ARM_PLT32: + case elfcpp::R_ARM_THM_XPC22: + case elfcpp::R_ARM_PREL31: + case elfcpp::R_ARM_SBREL31: + return false; + + default: + return true; + } + } + + private: + // Do a TLS relocation. + inline typename Arm_relocate_functions::Status + relocate_tls(const Relocate_info<32, big_endian>*, Target_arm*, + 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); + + }; + + // A class which returns the size required for a relocation type, + // used while scanning relocs during a relocatable link. + class Relocatable_size_for_reloc + { + public: + unsigned int + get_size_for_reloc(unsigned int, Relobj*); + }; + + // Adjust TLS relocation type based on the options and whether this + // is a local symbol. + static tls::Tls_optimization + optimize_tls_reloc(bool is_final, int r_type); + + // Get the GOT section, creating it if necessary. + Arm_output_data_got* + got_section(Symbol_table*, Layout*); + + // Get the GOT PLT section. + Output_data_space* + got_plt_section() const + { + gold_assert(this->got_plt_ != NULL); + return this->got_plt_; + } + + // Create a PLT entry for a global symbol. + void + make_plt_entry(Symbol_table*, Layout*, Symbol*); + + // Define the _TLS_MODULE_BASE_ symbol in the TLS segment. + void + define_tls_base_symbol(Symbol_table*, Layout*); + + // Create a GOT entry for the TLS module index. + unsigned int + got_mod_index_entry(Symbol_table* symtab, Layout* layout, + Sized_relobj_file<32, big_endian>* object); + + // Get the PLT section. + const Output_data_plt_arm* + plt_section() const + { + gold_assert(this->plt_ != NULL); + return this->plt_; + } + + // Get the dynamic reloc section, creating it if necessary. + Reloc_section* + rel_dyn_section(Layout*); + + // Get the section to use for TLS_DESC relocations. + Reloc_section* + rel_tls_desc_section(Layout*) const; + + // Return true if the symbol may need a COPY relocation. + // References from an executable object to non-function symbols + // defined in a dynamic object may need a COPY relocation. + bool + may_need_copy_reloc(Symbol* gsym) + { + return (gsym->type() != elfcpp::STT_ARM_TFUNC + && gsym->may_need_copy_reloc()); + } + + // Add a potential copy relocation. + void + copy_reloc(Symbol_table* symtab, Layout* layout, + Sized_relobj_file<32, big_endian>* object, + unsigned int shndx, Output_section* output_section, + Symbol* sym, const elfcpp::Rel<32, big_endian>& reloc) + { + this->copy_relocs_.copy_reloc(symtab, layout, + symtab->get_sized_symbol<32>(sym), + object, shndx, output_section, reloc, + this->rel_dyn_section(layout)); + } + + // Whether two EABI versions are compatible. + static bool + are_eabi_versions_compatible(elfcpp::Elf_Word v1, elfcpp::Elf_Word v2); + + // Merge processor-specific flags from input object and those in the ELF + // header of the output. + void + merge_processor_specific_flags(const std::string&, elfcpp::Elf_Word); + + // Get the secondary compatible architecture. + static int + get_secondary_compatible_arch(const Attributes_section_data*); + + // Set the secondary compatible architecture. + static void + set_secondary_compatible_arch(Attributes_section_data*, int); + + static int + tag_cpu_arch_combine(const char*, int, int*, int, int); + + // Helper to print AEABI enum tag value. + static std::string + aeabi_enum_name(unsigned int); + + // Return string value for TAG_CPU_name. + static std::string + tag_cpu_name_value(unsigned int); + + // Query attributes object to see if integer divide instructions may be + // present in an object. + static bool + attributes_accept_div(int arch, int profile, + const Object_attribute* div_attr); + + // Query attributes object to see if integer divide instructions are + // forbidden to be in the object. This is not the inverse of + // attributes_accept_div. + static bool + attributes_forbid_div(const Object_attribute* div_attr); + + // Merge object attributes from input object and those in the output. + void + merge_object_attributes(const char*, const Attributes_section_data*); + + // Helper to get an AEABI object attribute + Object_attribute* + get_aeabi_object_attribute(int tag) const + { + Attributes_section_data* pasd = this->attributes_section_data_; + gold_assert(pasd != NULL); + Object_attribute* attr = + pasd->get_attribute(Object_attribute::OBJ_ATTR_PROC, tag); + gold_assert(attr != NULL); + return attr; + } + + // + // Methods to support stub-generations. + // + + // Group input sections for stub generation. + void + group_sections(Layout*, section_size_type, bool, const Task*); + + // Scan a relocation for stub generation. + void + scan_reloc_for_stub(const Relocate_info<32, big_endian>*, unsigned int, + const Sized_symbol<32>*, unsigned int, + const Symbol_value<32>*, + elfcpp::Elf_types<32>::Elf_Swxword, Arm_address); + + // Scan a relocation section for stub. + template + void + scan_reloc_section_for_stubs( + const Relocate_info<32, big_endian>* relinfo, + const unsigned char* prelocs, + size_t reloc_count, + Output_section* output_section, + bool needs_special_offset_handling, + const unsigned char* view, + elfcpp::Elf_types<32>::Elf_Addr view_address, + section_size_type); + + // Fix .ARM.exidx section coverage. + void + fix_exidx_coverage(Layout*, const Input_objects*, + Arm_output_section*, Symbol_table*, + const Task*); + + // Functors for STL set. + struct output_section_address_less_than + { + bool + operator()(const Output_section* s1, const Output_section* s2) const + { return s1->address() < s2->address(); } + }; + + // Information about this specific target which we pass to the + // general Target structure. + static const Target::Target_info arm_info; + + // The types of GOT entries needed for this platform. + // These values are exposed to the ABI in an incremental link. + // Do not renumber existing values without changing the version + // number of the .gnu_incremental_inputs section. + enum Got_type + { + GOT_TYPE_STANDARD = 0, // GOT entry for a regular symbol + GOT_TYPE_TLS_NOFFSET = 1, // GOT entry for negative TLS offset + GOT_TYPE_TLS_OFFSET = 2, // GOT entry for positive TLS offset + GOT_TYPE_TLS_PAIR = 3, // GOT entry for TLS module/offset pair + GOT_TYPE_TLS_DESC = 4 // GOT entry for TLS_DESC pair + }; + + typedef typename std::vector*> Stub_table_list; + + // Map input section to Arm_input_section. + typedef Unordered_map*, + Section_id_hash> + Arm_input_section_map; + + // Map output addresses to relocs for Cortex-A8 erratum. + typedef Unordered_map + Cortex_a8_relocs_info; + + // The GOT section. + Arm_output_data_got* got_; + // The PLT section. + Output_data_plt_arm* plt_; + // The GOT PLT section. + Output_data_space* got_plt_; + // The dynamic reloc section. + Reloc_section* rel_dyn_; + // Relocs saved to avoid a COPY reloc. + Copy_relocs copy_relocs_; + // Offset of the GOT entry for the TLS module index. + unsigned int got_mod_index_offset_; + // True if the _TLS_MODULE_BASE_ symbol has been defined. + bool tls_base_symbol_defined_; + // Vector of Stub_tables created. + Stub_table_list stub_tables_; + // Stub factory. + const Stub_factory &stub_factory_; + // Whether we force PIC branch veneers. + bool should_force_pic_veneer_; + // Map for locating Arm_input_sections. + Arm_input_section_map arm_input_section_map_; + // Attributes section data in output. + Attributes_section_data* attributes_section_data_; + // Whether we want to fix code for Cortex-A8 erratum. + bool fix_cortex_a8_; + // Map addresses to relocs for Cortex-A8 erratum. + Cortex_a8_relocs_info cortex_a8_relocs_info_; +}; + +template +const Target::Target_info Target_arm::arm_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 + "/usr/lib/libc.so.1", // dynamic_linker + 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 + 0, // large_common_section_flags + ".ARM.attributes", // attributes_section + "aeabi", // attributes_vendor + "_start" // entry_symbol_name +}; + +// Arm relocate functions class +// + +template +class Arm_relocate_functions : public Relocate_functions<32, big_endian> +{ + public: + typedef enum + { + STATUS_OKAY, // No error during relocation. + STATUS_OVERFLOW, // Relocation overflow. + STATUS_BAD_RELOC // Relocation cannot be applied. + } Status; + + private: + typedef Relocate_functions<32, big_endian> Base; + typedef Arm_relocate_functions This; + + // 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 + // +-------+---------------+-------+-------+-----------------------+ + // | | |imm4 | |imm12 | + // +-------+---------------+-------+-------+-----------------------+ + + // Extract the relocation addend from VAL based on the ARM + // instruction encoding described above. + static inline typename elfcpp::Swap<32, big_endian>::Valtype + extract_arm_movw_movt_addend( + typename elfcpp::Swap<32, big_endian>::Valtype val) + { + // According to the Elf ABI for ARM Architecture the immediate + // field is sign-extended to form the addend. + return Bits<16>::sign_extend32(((val >> 4) & 0xf000) | (val & 0xfff)); + } + + // Insert X into VAL based on the ARM instruction encoding described + // above. + static inline typename elfcpp::Swap<32, big_endian>::Valtype + insert_val_arm_movw_movt( + typename elfcpp::Swap<32, big_endian>::Valtype val, + typename elfcpp::Swap<32, big_endian>::Valtype x) + { + val &= 0xfff0f000; + val |= x & 0x0fff; + val |= (x & 0xf000) << 4; + return val; + } + + // 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 + // +---------+-+-----------+-------++-+-----+-------+---------------+ + // | |i| |imm4 || |imm3 | |imm8 | + // +---------+-+-----------+-------++-+-----+-------+---------------+ + + // Extract the relocation addend from VAL based on the Thumb2 + // instruction encoding described above. + static inline typename elfcpp::Swap<32, big_endian>::Valtype + extract_thumb_movw_movt_addend( + typename elfcpp::Swap<32, big_endian>::Valtype val) + { + // According to the Elf ABI for ARM Architecture the immediate + // field is sign-extended to form the addend. + return Bits<16>::sign_extend32(((val >> 4) & 0xf000) + | ((val >> 15) & 0x0800) + | ((val >> 4) & 0x0700) + | (val & 0x00ff)); + } + + // Insert X into VAL based on the Thumb2 instruction encoding + // described above. + static inline typename elfcpp::Swap<32, big_endian>::Valtype + insert_val_thumb_movw_movt( + typename elfcpp::Swap<32, big_endian>::Valtype val, + typename elfcpp::Swap<32, big_endian>::Valtype x) + { + val &= 0xfbf08f00; + val |= (x & 0xf000) << 4; + val |= (x & 0x0800) << 15; + val |= (x & 0x0700) << 4; + val |= (x & 0x00ff); + return val; + } + + // Calculate the smallest constant Kn for the specified residual. + // (see (AAELF 4.6.1.4 Static ARM relocations, Group Relocations, p.32) + static uint32_t + calc_grp_kn(typename elfcpp::Swap<32, big_endian>::Valtype residual) + { + int32_t msb; + + if (residual == 0) + return 0; + // Determine the most significant bit in the residual and + // align the resulting value to a 2-bit boundary. + for (msb = 30; (msb >= 0) && !(residual & (3 << msb)); msb -= 2) + ; + // The desired shift is now (msb - 6), or zero, whichever + // is the greater. + return (((msb - 6) < 0) ? 0 : (msb - 6)); + } + + // Calculate the final residual for the specified group index. + // If the passed group index is less than zero, the method will return + // the value of the specified residual without any change. + // (see (AAELF 4.6.1.4 Static ARM relocations, Group Relocations, p.32) + static typename elfcpp::Swap<32, big_endian>::Valtype + calc_grp_residual(typename elfcpp::Swap<32, big_endian>::Valtype residual, + const int group) + { + for (int n = 0; n <= group; n++) + { + // Calculate which part of the value to mask. + uint32_t shift = calc_grp_kn(residual); + // Calculate the residual for the next time around. + residual &= ~(residual & (0xff << shift)); + } + + return residual; + } + + // Calculate the value of Gn for the specified group index. + // We return it in the form of an encoded constant-and-rotation. + // (see (AAELF 4.6.1.4 Static ARM relocations, Group Relocations, p.32) + static typename elfcpp::Swap<32, big_endian>::Valtype + calc_grp_gn(typename elfcpp::Swap<32, big_endian>::Valtype residual, + const int group) + { + typename elfcpp::Swap<32, big_endian>::Valtype gn = 0; + uint32_t shift = 0; + + for (int n = 0; n <= group; n++) + { + // Calculate which part of the value to mask. + shift = calc_grp_kn(residual); + // Calculate Gn in 32-bit as well as encoded constant-and-rotation form. + gn = residual & (0xff << shift); + // Calculate the residual for the next time around. + residual &= ~gn; + } + // Return Gn in the form of an encoded constant-and-rotation. + return ((gn >> shift) | ((gn <= 0xff ? 0 : (32 - shift) / 2) << 8)); + } + + public: + // Handle ARM long branches. + static typename This::Status + arm_branch_common(unsigned int, const Relocate_info<32, big_endian>*, + unsigned char*, const Sized_symbol<32>*, + const Arm_relobj*, unsigned int, + const Symbol_value<32>*, Arm_address, Arm_address, bool); + + // Handle THUMB long branches. + static typename This::Status + thumb_branch_common(unsigned int, const Relocate_info<32, big_endian>*, + unsigned char*, const Sized_symbol<32>*, + const Arm_relobj*, unsigned int, + const Symbol_value<32>*, Arm_address, Arm_address, bool); + + + // Return the branch offset of a 32-bit THUMB branch. + static inline int32_t + thumb32_branch_offset(uint16_t upper_insn, uint16_t lower_insn) + { + // We use the Thumb-2 encoding (backwards compatible with Thumb-1) + // involving the J1 and J2 bits. + uint32_t s = (upper_insn & (1U << 10)) >> 10; + uint32_t upper = upper_insn & 0x3ffU; + uint32_t lower = lower_insn & 0x7ffU; + uint32_t j1 = (lower_insn & (1U << 13)) >> 13; + uint32_t j2 = (lower_insn & (1U << 11)) >> 11; + uint32_t i1 = j1 ^ s ? 0 : 1; + uint32_t i2 = j2 ^ s ? 0 : 1; + + return Bits<25>::sign_extend32((s << 24) | (i1 << 23) | (i2 << 22) + | (upper << 12) | (lower << 1)); + } + + // Insert OFFSET to a 32-bit THUMB branch and return the upper instruction. + // UPPER_INSN is the original upper instruction of the branch. Caller is + // responsible for overflow checking and BLX offset adjustment. + static inline uint16_t + thumb32_branch_upper(uint16_t upper_insn, int32_t offset) + { + uint32_t s = offset < 0 ? 1 : 0; + uint32_t bits = static_cast(offset); + return (upper_insn & ~0x7ffU) | ((bits >> 12) & 0x3ffU) | (s << 10); + } + + // Insert OFFSET to a 32-bit THUMB branch and return the lower instruction. + // LOWER_INSN is the original lower instruction of the branch. Caller is + // responsible for overflow checking and BLX offset adjustment. + static inline uint16_t + thumb32_branch_lower(uint16_t lower_insn, int32_t offset) + { + uint32_t s = offset < 0 ? 1 : 0; + uint32_t bits = static_cast(offset); + return ((lower_insn & ~0x2fffU) + | ((((bits >> 23) & 1) ^ !s) << 13) + | ((((bits >> 22) & 1) ^ !s) << 11) + | ((bits >> 1) & 0x7ffU)); + } + + // Return the branch offset of a 32-bit THUMB conditional branch. + static inline int32_t + thumb32_cond_branch_offset(uint16_t upper_insn, uint16_t lower_insn) + { + uint32_t s = (upper_insn & 0x0400U) >> 10; + uint32_t j1 = (lower_insn & 0x2000U) >> 13; + uint32_t j2 = (lower_insn & 0x0800U) >> 11; + uint32_t lower = (lower_insn & 0x07ffU); + uint32_t upper = (s << 8) | (j2 << 7) | (j1 << 6) | (upper_insn & 0x003fU); + + return Bits<21>::sign_extend32((upper << 12) | (lower << 1)); + } + + // Insert OFFSET to a 32-bit THUMB conditional branch and return the upper + // instruction. UPPER_INSN is the original upper instruction of the branch. + // Caller is responsible for overflow checking. + static inline uint16_t + thumb32_cond_branch_upper(uint16_t upper_insn, int32_t offset) + { + uint32_t s = offset < 0 ? 1 : 0; + uint32_t bits = static_cast(offset); + return (upper_insn & 0xfbc0U) | (s << 10) | ((bits & 0x0003f000U) >> 12); + } + + // Insert OFFSET to a 32-bit THUMB conditional branch and return the lower + // instruction. LOWER_INSN is the original lower instruction of the branch. + // The caller is responsible for overflow checking. + static inline uint16_t + thumb32_cond_branch_lower(uint16_t lower_insn, int32_t offset) + { + uint32_t bits = static_cast(offset); + uint32_t j2 = (bits & 0x00080000U) >> 19; + uint32_t j1 = (bits & 0x00040000U) >> 18; + uint32_t lo = (bits & 0x00000ffeU) >> 1; + + return (lower_insn & 0xd000U) | (j1 << 13) | (j2 << 11) | lo; + } + + // R_ARM_ABS8: S + A + static inline typename This::Status + abs8(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, + const Symbol_value<32>* psymval) + { + typedef typename elfcpp::Swap<8, big_endian>::Valtype Valtype; + Valtype* wv = reinterpret_cast(view); + Valtype val = elfcpp::Swap<8, big_endian>::readval(wv); + int32_t addend = Bits<8>::sign_extend32(val); + Arm_address x = psymval->value(object, addend); + val = Bits<32>::bit_select32(val, x, 0xffU); + elfcpp::Swap<8, big_endian>::writeval(wv, val); + + // R_ARM_ABS8 permits signed or unsigned results. + return (Bits<8>::has_signed_unsigned_overflow32(x) + ? This::STATUS_OVERFLOW + : This::STATUS_OKAY); + } + + // R_ARM_THM_ABS5: S + A + static inline typename This::Status + thm_abs5(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, + const Symbol_value<32>* psymval) + { + typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype; + typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype; + Valtype* wv = reinterpret_cast(view); + Valtype val = elfcpp::Swap<16, big_endian>::readval(wv); + Reltype addend = (val & 0x7e0U) >> 6; + Reltype x = psymval->value(object, addend); + val = Bits<32>::bit_select32(val, x << 6, 0x7e0U); + elfcpp::Swap<16, big_endian>::writeval(wv, val); + return (Bits<5>::has_overflow32(x) + ? This::STATUS_OVERFLOW + : This::STATUS_OKAY); + } + + // R_ARM_ABS12: S + A + static inline typename This::Status + abs12(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, + const Symbol_value<32>* psymval) + { + typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype; + typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype; + Valtype* wv = reinterpret_cast(view); + Valtype val = elfcpp::Swap<32, big_endian>::readval(wv); + Reltype addend = val & 0x0fffU; + Reltype x = psymval->value(object, addend); + val = Bits<32>::bit_select32(val, x, 0x0fffU); + elfcpp::Swap<32, big_endian>::writeval(wv, val); + return (Bits<12>::has_overflow32(x) + ? This::STATUS_OVERFLOW + : This::STATUS_OKAY); + } + + // R_ARM_ABS16: S + A + static inline typename This::Status + abs16(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, + const Symbol_value<32>* psymval) + { + typedef typename elfcpp::Swap_unaligned<16, big_endian>::Valtype Valtype; + Valtype val = elfcpp::Swap_unaligned<16, big_endian>::readval(view); + int32_t addend = Bits<16>::sign_extend32(val); + Arm_address x = psymval->value(object, addend); + val = Bits<32>::bit_select32(val, x, 0xffffU); + elfcpp::Swap_unaligned<16, big_endian>::writeval(view, val); + + // R_ARM_ABS16 permits signed or unsigned results. + return (Bits<16>::has_signed_unsigned_overflow32(x) + ? This::STATUS_OVERFLOW + : This::STATUS_OKAY); + } + + // R_ARM_ABS32: (S + A) | T + static inline typename This::Status + abs32(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, + const Symbol_value<32>* psymval, + Arm_address thumb_bit) + { + typedef typename elfcpp::Swap_unaligned<32, big_endian>::Valtype Valtype; + Valtype addend = elfcpp::Swap_unaligned<32, big_endian>::readval(view); + Valtype x = psymval->value(object, addend) | thumb_bit; + elfcpp::Swap_unaligned<32, big_endian>::writeval(view, x); + return This::STATUS_OKAY; + } + + // R_ARM_REL32: (S + A) | T - P + static inline typename This::Status + rel32(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, + const Symbol_value<32>* psymval, + Arm_address address, + Arm_address thumb_bit) + { + typedef typename elfcpp::Swap_unaligned<32, big_endian>::Valtype Valtype; + Valtype addend = elfcpp::Swap_unaligned<32, big_endian>::readval(view); + Valtype x = (psymval->value(object, addend) | thumb_bit) - address; + elfcpp::Swap_unaligned<32, big_endian>::writeval(view, x); + return This::STATUS_OKAY; + } + + // R_ARM_THM_JUMP24: (S + A) | T - P + static typename This::Status + thm_jump19(unsigned char* view, const Arm_relobj* object, + const Symbol_value<32>* psymval, Arm_address address, + Arm_address thumb_bit); + + // R_ARM_THM_JUMP6: S + A – P + static inline typename This::Status + thm_jump6(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, + const Symbol_value<32>* psymval, + Arm_address address) + { + typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype; + typedef typename elfcpp::Swap<16, big_endian>::Valtype Reltype; + Valtype* wv = reinterpret_cast(view); + Valtype val = elfcpp::Swap<16, big_endian>::readval(wv); + // bit[9]:bit[7:3]:’0’ (mask: 0x02f8) + Reltype addend = (((val & 0x0200) >> 3) | ((val & 0x00f8) >> 2)); + Reltype x = (psymval->value(object, addend) - address); + val = (val & 0xfd07) | ((x & 0x0040) << 3) | ((val & 0x003e) << 2); + elfcpp::Swap<16, big_endian>::writeval(wv, val); + // CZB does only forward jumps. + return ((x > 0x007e) + ? This::STATUS_OVERFLOW + : This::STATUS_OKAY); + } + + // R_ARM_THM_JUMP8: S + A – P + static inline typename This::Status + thm_jump8(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, + const Symbol_value<32>* psymval, + Arm_address address) + { + typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype; + Valtype* wv = reinterpret_cast(view); + Valtype val = elfcpp::Swap<16, big_endian>::readval(wv); + 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))); + // We do a 9-bit overflow check because x is right-shifted by 1 bit. + return (Bits<9>::has_overflow32(x) + ? This::STATUS_OVERFLOW + : This::STATUS_OKAY); + } + + // R_ARM_THM_JUMP11: S + A – P + static inline typename This::Status + thm_jump11(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, + const Symbol_value<32>* psymval, + Arm_address address) + { + typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype; + Valtype* wv = reinterpret_cast(view); + Valtype val = elfcpp::Swap<16, big_endian>::readval(wv); + 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))); + // We do a 12-bit overflow check because x is right-shifted by 1 bit. + return (Bits<12>::has_overflow32(x) + ? This::STATUS_OVERFLOW + : This::STATUS_OKAY); + } + + // R_ARM_BASE_PREL: B(S) + A - P + static inline typename This::Status + base_prel(unsigned char* view, + Arm_address origin, + Arm_address address) + { + Base::rel32(view, origin - address); + return STATUS_OKAY; + } + + // R_ARM_BASE_ABS: B(S) + A + static inline typename This::Status + base_abs(unsigned char* view, + Arm_address origin) + { + Base::rel32(view, origin); + return STATUS_OKAY; + } + + // R_ARM_GOT_BREL: GOT(S) + A - GOT_ORG + static inline typename This::Status + got_brel(unsigned char* view, + typename elfcpp::Swap<32, big_endian>::Valtype got_offset) + { + Base::rel32(view, got_offset); + return This::STATUS_OKAY; + } + + // R_ARM_GOT_PREL: GOT(S) + A - P + static inline typename This::Status + got_prel(unsigned char* view, + Arm_address got_entry, + Arm_address address) + { + Base::rel32(view, got_entry - address); + return This::STATUS_OKAY; + } + + // R_ARM_PREL: (S + A) | T - P + static inline typename This::Status + prel31(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, + const Symbol_value<32>* psymval, + Arm_address address, + Arm_address thumb_bit) + { + typedef typename elfcpp::Swap_unaligned<32, big_endian>::Valtype Valtype; + Valtype val = elfcpp::Swap_unaligned<32, big_endian>::readval(view); + Valtype addend = Bits<31>::sign_extend32(val); + Valtype x = (psymval->value(object, addend) | thumb_bit) - address; + val = Bits<32>::bit_select32(val, x, 0x7fffffffU); + elfcpp::Swap_unaligned<32, big_endian>::writeval(view, val); + return (Bits<31>::has_overflow32(x) + ? This::STATUS_OVERFLOW + : This::STATUS_OKAY); + } + + // R_ARM_MOVW_ABS_NC: (S + A) | T (relative address base is ) + // R_ARM_MOVW_PREL_NC: (S + A) | T - P + // R_ARM_MOVW_BREL_NC: ((S + A) | T) - B(S) + // R_ARM_MOVW_BREL: ((S + A) | T) - B(S) + static inline typename This::Status + movw(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, + const Symbol_value<32>* psymval, + Arm_address relative_address_base, + Arm_address thumb_bit, + bool check_overflow) + { + typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype; + Valtype* wv = reinterpret_cast(view); + Valtype val = elfcpp::Swap<32, big_endian>::readval(wv); + Valtype addend = This::extract_arm_movw_movt_addend(val); + Valtype x = ((psymval->value(object, addend) | thumb_bit) + - relative_address_base); + val = This::insert_val_arm_movw_movt(val, x); + elfcpp::Swap<32, big_endian>::writeval(wv, val); + return ((check_overflow && Bits<16>::has_overflow32(x)) + ? This::STATUS_OVERFLOW + : This::STATUS_OKAY); + } + + // R_ARM_MOVT_ABS: S + A (relative address base is 0) + // R_ARM_MOVT_PREL: S + A - P + // R_ARM_MOVT_BREL: S + A - B(S) + static inline typename This::Status + movt(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, + const Symbol_value<32>* psymval, + Arm_address relative_address_base) + { + typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype; + Valtype* wv = reinterpret_cast(view); + Valtype val = elfcpp::Swap<32, big_endian>::readval(wv); + Valtype addend = This::extract_arm_movw_movt_addend(val); + Valtype x = (psymval->value(object, addend) - relative_address_base) >> 16; + val = This::insert_val_arm_movw_movt(val, x); + elfcpp::Swap<32, big_endian>::writeval(wv, val); + // FIXME: IHI0044D says that we should check for overflow. + return This::STATUS_OKAY; + } + + // R_ARM_THM_MOVW_ABS_NC: S + A | T (relative_address_base is 0) + // R_ARM_THM_MOVW_PREL_NC: (S + A) | T - P + // R_ARM_THM_MOVW_BREL_NC: ((S + A) | T) - B(S) + // R_ARM_THM_MOVW_BREL: ((S + A) | T) - B(S) + static inline typename This::Status + thm_movw(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, + const Symbol_value<32>* psymval, + Arm_address relative_address_base, + Arm_address thumb_bit, + bool check_overflow) + { + typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype; + typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype; + Valtype* wv = reinterpret_cast(view); + Reltype val = (elfcpp::Swap<16, big_endian>::readval(wv) << 16) + | elfcpp::Swap<16, big_endian>::readval(wv + 1); + Reltype addend = This::extract_thumb_movw_movt_addend(val); + Reltype x = + (psymval->value(object, addend) | thumb_bit) - relative_address_base; + val = This::insert_val_thumb_movw_movt(val, x); + 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_OKAY); + } + + // R_ARM_THM_MOVT_ABS: S + A (relative address base is 0) + // R_ARM_THM_MOVT_PREL: S + A - P + // R_ARM_THM_MOVT_BREL: S + A - B(S) + static inline typename This::Status + thm_movt(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, + const Symbol_value<32>* psymval, + Arm_address relative_address_base) + { + typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype; + typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype; + Valtype* wv = reinterpret_cast(view); + Reltype val = (elfcpp::Swap<16, big_endian>::readval(wv) << 16) + | elfcpp::Swap<16, big_endian>::readval(wv + 1); + Reltype addend = This::extract_thumb_movw_movt_addend(val); + Reltype x = (psymval->value(object, addend) - relative_address_base) >> 16; + val = This::insert_val_thumb_movw_movt(val, x); + elfcpp::Swap<16, big_endian>::writeval(wv, val >> 16); + elfcpp::Swap<16, big_endian>::writeval(wv + 1, val & 0xffff); + return This::STATUS_OKAY; + } + + // R_ARM_THM_ALU_PREL_11_0: ((S + A) | T) - Pa (Thumb32) + static inline typename This::Status + thm_alu11(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, + const Symbol_value<32>* psymval, + Arm_address address, + Arm_address thumb_bit) + { + typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype; + typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype; + Valtype* wv = reinterpret_cast(view); + Reltype insn = (elfcpp::Swap<16, big_endian>::readval(wv) << 16) + | elfcpp::Swap<16, big_endian>::readval(wv + 1); + + // 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 + // ----------------------------------------------------------------------- + // ADD{S} 1 1 1 1 0|i|0|1 0 0 0|S|1 1 0 1||0|imm3 |Rd |imm8 + // ADDW 1 1 1 1 0|i|1|0 0 0 0|0|1 1 0 1||0|imm3 |Rd |imm8 + // ADR[+] 1 1 1 1 0|i|1|0 0 0 0|0|1 1 1 1||0|imm3 |Rd |imm8 + // SUB{S} 1 1 1 1 0|i|0|1 1 0 1|S|1 1 0 1||0|imm3 |Rd |imm8 + // SUBW 1 1 1 1 0|i|1|0 1 0 1|0|1 1 0 1||0|imm3 |Rd |imm8 + // ADR[-] 1 1 1 1 0|i|1|0 1 0 1|0|1 1 1 1||0|imm3 |Rd |imm8 + + // Determine a sign for the addend. + const int sign = ((insn & 0xf8ef0000) == 0xf0ad0000 + || (insn & 0xf8ef0000) == 0xf0af0000) ? -1 : 1; + // Thumb2 addend encoding: + // imm12 := i | imm3 | imm8 + int32_t addend = (insn & 0xff) + | ((insn & 0x00007000) >> 4) + | ((insn & 0x04000000) >> 15); + // Apply a sign to the added. + addend *= sign; + + int32_t x = (psymval->value(object, addend) | thumb_bit) + - (address & 0xfffffffc); + Reltype val = abs(x); + // Mask out the value and a distinct part of the ADD/SUB opcode + // (bits 7:5 of opword). + insn = (insn & 0xfb0f8f00) + | (val & 0xff) + | ((val & 0x700) << 4) + | ((val & 0x800) << 15); + // Set the opcode according to whether the value to go in the + // place is negative. + if (x < 0) + insn |= 0x00a00000; + + 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); + } + + // R_ARM_THM_PC8: S + A - Pa (Thumb) + static inline typename This::Status + thm_pc8(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, + const Symbol_value<32>* psymval, + Arm_address address) + { + typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype; + typedef typename elfcpp::Swap<16, big_endian>::Valtype Reltype; + Valtype* wv = reinterpret_cast(view); + Valtype insn = elfcpp::Swap<16, big_endian>::readval(wv); + Reltype addend = ((insn & 0x00ff) << 2); + int32_t x = (psymval->value(object, addend) - (address & 0xfffffffc)); + Reltype val = abs(x); + insn = (insn & 0xff00) | ((val & 0x03fc) >> 2); + + elfcpp::Swap<16, big_endian>::writeval(wv, insn); + return ((val > 0x03fc) + ? This::STATUS_OVERFLOW + : This::STATUS_OKAY); + } + + // R_ARM_THM_PC12: S + A - Pa (Thumb32) + static inline typename This::Status + thm_pc12(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, + const Symbol_value<32>* psymval, + Arm_address address) + { + typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype; + typedef typename elfcpp::Swap<32, big_endian>::Valtype Reltype; + Valtype* wv = reinterpret_cast(view); + Reltype insn = (elfcpp::Swap<16, big_endian>::readval(wv) << 16) + | elfcpp::Swap<16, big_endian>::readval(wv + 1); + // Determine a sign for the addend (positive if the U bit is 1). + const int sign = (insn & 0x00800000) ? 1 : -1; + int32_t addend = (insn & 0xfff); + // Apply a sign to the added. + addend *= sign; + + int32_t x = (psymval->value(object, addend) - (address & 0xfffffffc)); + Reltype val = abs(x); + // Mask out and apply the value and the U bit. + insn = (insn & 0xff7ff000) | (val & 0xfff); + // Set the U bit according to whether the value to go in the + // place is positive. + if (x >= 0) + insn |= 0x00800000; + + 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); + } + + // R_ARM_V4BX + static inline typename This::Status + v4bx(const Relocate_info<32, big_endian>* relinfo, + unsigned char* view, + const Arm_relobj* object, + const Arm_address address, + const bool is_interworking) + { + + typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype; + Valtype* wv = reinterpret_cast(view); + Valtype val = elfcpp::Swap<32, big_endian>::readval(wv); + + // Ensure that we have a BX instruction. + gold_assert((val & 0x0ffffff0) == 0x012fff10); + const uint32_t reg = (val & 0xf); + if (is_interworking && reg != 0xf) + { + Stub_table* stub_table = + object->stub_table(relinfo->data_shndx); + gold_assert(stub_table != NULL); + + Arm_v4bx_stub* stub = stub_table->find_arm_v4bx_stub(reg); + gold_assert(stub != NULL); + + int32_t veneer_address = + stub_table->address() + stub->offset() - 8 - address; + gold_assert((veneer_address <= ARM_MAX_FWD_BRANCH_OFFSET) + && (veneer_address >= ARM_MAX_BWD_BRANCH_OFFSET)); + // Replace with a branch to veneer (B ) + val = (val & 0xf0000000) | 0x0a000000 + | ((veneer_address >> 2) & 0x00ffffff); + } + else + { + // Preserve Rm (lowest four bits) and the condition code + // (highest four bits). Other bits encode MOV PC,Rm. + val = (val & 0xf000000f) | 0x01a0f000; + } + elfcpp::Swap<32, big_endian>::writeval(wv, val); + return This::STATUS_OKAY; + } + + // R_ARM_ALU_PC_G0_NC: ((S + A) | T) - P + // R_ARM_ALU_PC_G0: ((S + A) | T) - P + // R_ARM_ALU_PC_G1_NC: ((S + A) | T) - P + // R_ARM_ALU_PC_G1: ((S + A) | T) - P + // R_ARM_ALU_PC_G2: ((S + A) | T) - P + // R_ARM_ALU_SB_G0_NC: ((S + A) | T) - B(S) + // R_ARM_ALU_SB_G0: ((S + A) | T) - B(S) + // R_ARM_ALU_SB_G1_NC: ((S + A) | T) - B(S) + // R_ARM_ALU_SB_G1: ((S + A) | T) - B(S) + // R_ARM_ALU_SB_G2: ((S + A) | T) - B(S) + static inline typename This::Status + arm_grp_alu(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, + const Symbol_value<32>* psymval, + const int group, + Arm_address address, + Arm_address thumb_bit, + bool check_overflow) + { + gold_assert(group >= 0 && group < 3); + typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype; + Valtype* wv = reinterpret_cast(view); + Valtype insn = elfcpp::Swap<32, big_endian>::readval(wv); + + // ALU group relocations are allowed only for the ADD/SUB instructions. + // (0x00800000 - ADD, 0x00400000 - SUB) + const Valtype opcode = insn & 0x01e00000; + if (opcode != 0x00800000 && opcode != 0x00400000) + return This::STATUS_BAD_RELOC; + + // Determine a sign for the addend. + const int sign = (opcode == 0x00800000) ? 1 : -1; + // shifter = rotate_imm * 2 + const uint32_t shifter = (insn & 0xf00) >> 7; + // Initial addend value. + int32_t addend = insn & 0xff; + // Rotate addend right by shifter. + addend = (addend >> shifter) | (addend << (32 - shifter)); + // Apply a sign to the added. + addend *= sign; + + int32_t x = ((psymval->value(object, addend) | thumb_bit) - address); + Valtype gn = Arm_relocate_functions::calc_grp_gn(abs(x), group); + // Check for overflow if required + if (check_overflow + && (Arm_relocate_functions::calc_grp_residual(abs(x), group) != 0)) + return This::STATUS_OVERFLOW; + + // Mask out the value and the ADD/SUB part of the opcode; take care + // not to destroy the S bit. + insn &= 0xff1ff000; + // Set the opcode according to whether the value to go in the + // place is negative. + insn |= ((x < 0) ? 0x00400000 : 0x00800000); + // Encode the offset (encoded Gn). + insn |= gn; + + elfcpp::Swap<32, big_endian>::writeval(wv, insn); + return This::STATUS_OKAY; + } + + // R_ARM_LDR_PC_G0: S + A - P + // R_ARM_LDR_PC_G1: S + A - P + // R_ARM_LDR_PC_G2: S + A - P + // R_ARM_LDR_SB_G0: S + A - B(S) + // R_ARM_LDR_SB_G1: S + A - B(S) + // R_ARM_LDR_SB_G2: S + A - B(S) + static inline typename This::Status + arm_grp_ldr(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, + const Symbol_value<32>* psymval, + const int group, + Arm_address address) + { + gold_assert(group >= 0 && group < 3); + typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype; + Valtype* wv = reinterpret_cast(view); + Valtype insn = elfcpp::Swap<32, big_endian>::readval(wv); + + const int sign = (insn & 0x00800000) ? 1 : -1; + int32_t addend = (insn & 0xfff) * sign; + int32_t x = (psymval->value(object, addend) - address); + // Calculate the relevant G(n-1) value to obtain this stage residual. + Valtype residual = + Arm_relocate_functions::calc_grp_residual(abs(x), group - 1); + if (residual >= 0x1000) + return This::STATUS_OVERFLOW; + + // Mask out the value and U bit. + insn &= 0xff7ff000; + // Set the U bit for non-negative values. + if (x >= 0) + insn |= 0x00800000; + insn |= residual; + + elfcpp::Swap<32, big_endian>::writeval(wv, insn); + return This::STATUS_OKAY; + } + + // R_ARM_LDRS_PC_G0: S + A - P + // R_ARM_LDRS_PC_G1: S + A - P + // R_ARM_LDRS_PC_G2: S + A - P + // R_ARM_LDRS_SB_G0: S + A - B(S) + // R_ARM_LDRS_SB_G1: S + A - B(S) + // R_ARM_LDRS_SB_G2: S + A - B(S) + static inline typename This::Status + arm_grp_ldrs(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, + const Symbol_value<32>* psymval, + const int group, + Arm_address address) + { + gold_assert(group >= 0 && group < 3); + typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype; + Valtype* wv = reinterpret_cast(view); + Valtype insn = elfcpp::Swap<32, big_endian>::readval(wv); + + const int sign = (insn & 0x00800000) ? 1 : -1; + int32_t addend = (((insn & 0xf00) >> 4) + (insn & 0xf)) * sign; + int32_t x = (psymval->value(object, addend) - address); + // Calculate the relevant G(n-1) value to obtain this stage residual. + Valtype residual = + Arm_relocate_functions::calc_grp_residual(abs(x), group - 1); + if (residual >= 0x100) + return This::STATUS_OVERFLOW; + + // Mask out the value and U bit. + insn &= 0xff7ff0f0; + // Set the U bit for non-negative values. + if (x >= 0) + insn |= 0x00800000; + insn |= ((residual & 0xf0) << 4) | (residual & 0xf); + + elfcpp::Swap<32, big_endian>::writeval(wv, insn); + return This::STATUS_OKAY; + } + + // R_ARM_LDC_PC_G0: S + A - P + // R_ARM_LDC_PC_G1: S + A - P + // R_ARM_LDC_PC_G2: S + A - P + // R_ARM_LDC_SB_G0: S + A - B(S) + // R_ARM_LDC_SB_G1: S + A - B(S) + // R_ARM_LDC_SB_G2: S + A - B(S) + static inline typename This::Status + arm_grp_ldc(unsigned char* view, + const Sized_relobj_file<32, big_endian>* object, + const Symbol_value<32>* psymval, + const int group, + Arm_address address) + { + gold_assert(group >= 0 && group < 3); + typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype; + Valtype* wv = reinterpret_cast(view); + Valtype insn = elfcpp::Swap<32, big_endian>::readval(wv); + + const int sign = (insn & 0x00800000) ? 1 : -1; + int32_t addend = ((insn & 0xff) << 2) * sign; + int32_t x = (psymval->value(object, addend) - address); + // Calculate the relevant G(n-1) value to obtain this stage residual. + Valtype residual = + Arm_relocate_functions::calc_grp_residual(abs(x), group - 1); + if ((residual & 0x3) != 0 || residual >= 0x400) + return This::STATUS_OVERFLOW; + + // Mask out the value and U bit. + insn &= 0xff7fff00; + // Set the U bit for non-negative values. + if (x >= 0) + insn |= 0x00800000; + insn |= (residual >> 2); + + elfcpp::Swap<32, big_endian>::writeval(wv, insn); + return This::STATUS_OKAY; + } +}; + +// Relocate ARM long branches. This handles relocation types +// R_ARM_CALL, R_ARM_JUMP24, R_ARM_PLT32 and R_ARM_XPC25. +// If IS_WEAK_UNDEFINED_WITH_PLT is true. The target symbol is weakly +// undefined and we do not use PLT in this relocation. In such a case, +// the branch is converted into an NOP. + +template +typename Arm_relocate_functions::Status +Arm_relocate_functions::arm_branch_common( + unsigned int r_type, + const Relocate_info<32, big_endian>* relinfo, + unsigned char* view, + const Sized_symbol<32>* gsym, + const Arm_relobj* object, + unsigned int r_sym, + const Symbol_value<32>* psymval, + Arm_address address, + Arm_address thumb_bit, + bool is_weakly_undefined_without_plt) +{ + typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype; + Valtype* wv = reinterpret_cast(view); + Valtype val = elfcpp::Swap<32, big_endian>::readval(wv); + + bool insn_is_b = (((val >> 28) & 0xf) <= 0xe) + && ((val & 0x0f000000UL) == 0x0a000000UL); + bool insn_is_uncond_bl = (val & 0xff000000UL) == 0xeb000000UL; + bool insn_is_cond_bl = (((val >> 28) & 0xf) < 0xe) + && ((val & 0x0f000000UL) == 0x0b000000UL); + bool insn_is_blx = (val & 0xfe000000UL) == 0xfa000000UL; + bool insn_is_any_branch = (val & 0x0e000000UL) == 0x0a000000UL; + + // Check that the instruction is valid. + if (r_type == elfcpp::R_ARM_CALL) + { + if (!insn_is_uncond_bl && !insn_is_blx) + return This::STATUS_BAD_RELOC; + } + else if (r_type == elfcpp::R_ARM_JUMP24) + { + if (!insn_is_b && !insn_is_cond_bl) + return This::STATUS_BAD_RELOC; + } + else if (r_type == elfcpp::R_ARM_PLT32) + { + if (!insn_is_any_branch) + return This::STATUS_BAD_RELOC; + } + else if (r_type == elfcpp::R_ARM_XPC25) + { + // FIXME: AAELF document IH0044C does not say much about it other + // than it being obsolete. + if (!insn_is_any_branch) + return This::STATUS_BAD_RELOC; + } + else + gold_unreachable(); + + // A branch to an undefined weak symbol is turned into a jump to + // the next instruction unless a PLT entry will be created. + // Do the same for local undefined symbols. + // The jump to the next instruction is optimized as a NOP depending + // on the architecture. + const Target_arm* arm_target = + Target_arm::default_target(); + if (is_weakly_undefined_without_plt) + { + gold_assert(!parameters->options().relocatable()); + Valtype cond = val & 0xf0000000U; + if (arm_target->may_use_arm_nop()) + val = cond | 0x0320f000; + else + val = cond | 0x01a00000; // Using pre-UAL nop: mov r0, r0. + 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; + + // We need a stub if the branch offset is too large or if we need + // to switch mode. + bool may_use_blx = arm_target->may_use_v5t_interworking(); + Reloc_stub* stub = NULL; + + if (!parameters->options().relocatable() + && (Bits<26>::has_overflow32(branch_offset) + || ((thumb_bit != 0) + && !(may_use_blx && r_type == elfcpp::R_ARM_CALL)))) + { + Valtype unadjusted_branch_target = psymval->value(object, 0); + + Stub_type stub_type = + Reloc_stub::stub_type_for_reloc(r_type, address, + unadjusted_branch_target, + (thumb_bit != 0)); + if (stub_type != arm_stub_none) + { + Stub_table* stub_table = + object->stub_table(relinfo->data_shndx); + gold_assert(stub_table != NULL); + + Reloc_stub::Key stub_key(stub_type, gsym, object, r_sym, addend); + stub = stub_table->find_reloc_stub(stub_key); + gold_assert(stub != NULL); + thumb_bit = stub->stub_template()->entry_in_thumb_mode() ? 1 : 0; + branch_target = stub_table->address() + stub->offset() + addend; + branch_offset = branch_target - address; + gold_assert(!Bits<26>::has_overflow32(branch_offset)); + } + } + + // At this point, if we still need to switch mode, the instruction + // must either be a BLX or a BL that can be converted to a BLX. + if (thumb_bit != 0) + { + // Turn BL to BLX. + gold_assert(may_use_blx && r_type == elfcpp::R_ARM_CALL); + val = (val & 0xffffff) | 0xfa000000 | ((branch_offset & 2) << 23); + } + + val = Bits<32>::bit_select32(val, (branch_offset >> 2), 0xffffffUL); + elfcpp::Swap<32, big_endian>::writeval(wv, val); + return (Bits<26>::has_overflow32(branch_offset) + ? This::STATUS_OVERFLOW + : This::STATUS_OKAY); +} + +// Relocate THUMB long branches. This handles relocation types +// R_ARM_THM_CALL, R_ARM_THM_JUMP24 and R_ARM_THM_XPC22. +// If IS_WEAK_UNDEFINED_WITH_PLT is true. The target symbol is weakly +// undefined and we do not use PLT in this relocation. In such a case, +// the branch is converted into an NOP. + +template +typename Arm_relocate_functions::Status +Arm_relocate_functions::thumb_branch_common( + unsigned int r_type, + const Relocate_info<32, big_endian>* relinfo, + unsigned char* view, + const Sized_symbol<32>* gsym, + const Arm_relobj* object, + unsigned int r_sym, + const Symbol_value<32>* psymval, + Arm_address address, + Arm_address thumb_bit, + bool is_weakly_undefined_without_plt) +{ + typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype; + Valtype* wv = reinterpret_cast(view); + uint32_t upper_insn = elfcpp::Swap<16, big_endian>::readval(wv); + uint32_t lower_insn = elfcpp::Swap<16, big_endian>::readval(wv + 1); + + // FIXME: These tests are too loose and do not take THUMB/THUMB-2 difference + // 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) + { + if (!is_bl_insn && !is_blx_insn) + return This::STATUS_BAD_RELOC; + } + else if (r_type == elfcpp::R_ARM_THM_JUMP24) + { + // This cannot be a BLX. + if (!is_bl_insn) + return This::STATUS_BAD_RELOC; + } + else if (r_type == elfcpp::R_ARM_THM_XPC22) + { + // Check for Thumb to Thumb call. + if (!is_blx_insn) + return This::STATUS_BAD_RELOC; + if (thumb_bit != 0) + { + gold_warning(_("%s: Thumb BLX instruction targets " + "thumb function '%s'."), + object->name().c_str(), + (gsym ? gsym->name() : "(local)")); + // Convert BLX to BL. + lower_insn |= 0x1000U; + } + } + else + gold_unreachable(); + + // A branch to an undefined weak symbol is turned into a jump to + // the next instruction unless a PLT entry will be created. + // The jump to the next instruction is optimized as a NOP.W for + // Thumb-2 enabled architectures. + const Target_arm* arm_target = + Target_arm::default_target(); + if (is_weakly_undefined_without_plt) + { + gold_assert(!parameters->options().relocatable()); + if (arm_target->may_use_thumb2_nop()) + { + elfcpp::Swap<16, big_endian>::writeval(wv, 0xf3af); + elfcpp::Swap<16, big_endian>::writeval(wv + 1, 0x8000); + } + else + { + elfcpp::Swap<16, big_endian>::writeval(wv, 0xe000); + elfcpp::Swap<16, big_endian>::writeval(wv + 1, 0xbf00); + } + return This::STATUS_OKAY; + } + + int32_t addend = This::thumb32_branch_offset(upper_insn, lower_insn); + Arm_address branch_target = psymval->value(object, addend); + + // For BLX, bit 1 of target address comes from bit 1 of base address. + bool may_use_blx = arm_target->may_use_v5t_interworking(); + if (thumb_bit == 0 && may_use_blx) + branch_target = Bits<32>::bit_select32(branch_target, address, 0x2); + + int32_t branch_offset = branch_target - address; + + // We need a stub if the branch offset is too large or if we need + // to switch mode. + bool thumb2 = arm_target->using_thumb2(); + if (!parameters->options().relocatable() + && ((!thumb2 && Bits<23>::has_overflow32(branch_offset)) + || (thumb2 && Bits<25>::has_overflow32(branch_offset)) + || ((thumb_bit == 0) + && (((r_type == elfcpp::R_ARM_THM_CALL) && !may_use_blx) + || r_type == elfcpp::R_ARM_THM_JUMP24)))) + { + Arm_address unadjusted_branch_target = psymval->value(object, 0); + + Stub_type stub_type = + Reloc_stub::stub_type_for_reloc(r_type, address, + unadjusted_branch_target, + (thumb_bit != 0)); + + if (stub_type != arm_stub_none) + { + Stub_table* stub_table = + object->stub_table(relinfo->data_shndx); + gold_assert(stub_table != NULL); + + Reloc_stub::Key stub_key(stub_type, gsym, object, r_sym, addend); + Reloc_stub* stub = stub_table->find_reloc_stub(stub_key); + 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) + branch_target = Bits<32>::bit_select32(branch_target, address, 0x2); + branch_offset = branch_target - address; + } + } + + // At this point, if we still need to switch mode, the instruction + // must either be a BLX or a BL that can be converted to a BLX. + if (thumb_bit == 0) + { + gold_assert(may_use_blx + && (r_type == elfcpp::R_ARM_THM_CALL + || r_type == elfcpp::R_ARM_THM_XPC22)); + // Make sure this is a BLX. + lower_insn &= ~0x1000U; + } + else + { + // Make sure this is a BL. + lower_insn |= 0x1000U; + } + + // For a BLX instruction, make sure that the relocation is rounded up + // to a word boundary. This follows the semantics of the instruction + // which specifies that bit 1 of the target address will come from bit + // 1 of the base address. + if ((lower_insn & 0x5000U) == 0x4000U) + gold_assert((branch_offset & 3) == 0); + + // Put BRANCH_OFFSET back into the insn. Assumes two's complement. + // We use the Thumb-2 encoding, which is safe even if dealing with + // a Thumb-1 instruction by virtue of our overflow check above. */ + upper_insn = This::thumb32_branch_upper(upper_insn, branch_offset); + lower_insn = This::thumb32_branch_lower(lower_insn, branch_offset); + + elfcpp::Swap<16, big_endian>::writeval(wv, upper_insn); + elfcpp::Swap<16, big_endian>::writeval(wv + 1, lower_insn); + + gold_assert(!Bits<25>::has_overflow32(branch_offset)); + + return ((thumb2 + ? Bits<25>::has_overflow32(branch_offset) + : Bits<23>::has_overflow32(branch_offset)) + ? This::STATUS_OVERFLOW + : This::STATUS_OKAY); +} + +// Relocate THUMB-2 long conditional branches. +// If IS_WEAK_UNDEFINED_WITH_PLT is true. The target symbol is weakly +// undefined and we do not use PLT in this relocation. In such a case, +// the branch is converted into an NOP. + +template +typename Arm_relocate_functions::Status +Arm_relocate_functions::thm_jump19( + unsigned char* view, + const Arm_relobj* object, + const Symbol_value<32>* psymval, + Arm_address address, + Arm_address thumb_bit) +{ + typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype; + Valtype* wv = reinterpret_cast(view); + uint32_t upper_insn = elfcpp::Swap<16, big_endian>::readval(wv); + uint32_t lower_insn = elfcpp::Swap<16, big_endian>::readval(wv + 1); + int32_t addend = This::thumb32_cond_branch_offset(upper_insn, lower_insn); + + Arm_address branch_target = psymval->value(object, addend); + int32_t branch_offset = branch_target - address; + + // ??? Should handle interworking? GCC might someday try to + // use this for tail calls. + // FIXME: We do support thumb entry to PLT yet. + if (thumb_bit == 0) + { + gold_error(_("conditional branch to PLT in THUMB-2 not supported yet.")); + return This::STATUS_BAD_RELOC; + } + + // Put RELOCATION back into the insn. + upper_insn = This::thumb32_cond_branch_upper(upper_insn, branch_offset); + lower_insn = This::thumb32_cond_branch_lower(lower_insn, branch_offset); + + // Put the relocated value back in the object file: + elfcpp::Swap<16, big_endian>::writeval(wv, upper_insn); + elfcpp::Swap<16, big_endian>::writeval(wv + 1, lower_insn); + + return (Bits<21>::has_overflow32(branch_offset) + ? This::STATUS_OVERFLOW + : This::STATUS_OKAY); +} + +// Get the GOT section, creating it if necessary. + +template +Arm_output_data_got* +Target_arm::got_section(Symbol_table* symtab, Layout* layout) +{ + if (this->got_ == NULL) + { + gold_assert(symtab != NULL && layout != NULL); + + // When using -z now, we can treat .got as a relro section. + // Without -z now, it is modified after program startup by lazy + // PLT relocations. + bool is_got_relro = parameters->options().now(); + Output_section_order got_order = (is_got_relro + ? ORDER_RELRO_LAST + : ORDER_DATA); + + // Unlike some targets (.e.g x86), ARM does not use separate .got and + // .got.plt sections in output. The output .got section contains both + // PLT and non-PLT GOT entries. + this->got_ = new Arm_output_data_got(symtab, layout); + + layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS, + (elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE), + this->got_, got_order, is_got_relro); + + // The old GNU linker creates a .got.plt section. We just + // create another set of data in the .got section. Note that we + // always create a PLT if we create a GOT, although the PLT + // might be empty. + this->got_plt_ = new Output_data_space(4, "** GOT PLT"); + layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS, + (elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE), + this->got_plt_, got_order, is_got_relro); + + // The first three entries are reserved. + this->got_plt_->set_current_data_size(3 * 4); + + // Define _GLOBAL_OFFSET_TABLE_ at the start of the PLT. + symtab->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL, + Symbol_table::PREDEFINED, + this->got_plt_, + 0, 0, elfcpp::STT_OBJECT, + elfcpp::STB_LOCAL, + elfcpp::STV_HIDDEN, 0, + false, false); + } + return this->got_; +} + +// Get the dynamic reloc section, creating it if necessary. + +template +typename Target_arm::Reloc_section* +Target_arm::rel_dyn_section(Layout* layout) +{ + if (this->rel_dyn_ == NULL) + { + gold_assert(layout != NULL); + this->rel_dyn_ = new Reloc_section(parameters->options().combreloc()); + layout->add_output_section_data(".rel.dyn", elfcpp::SHT_REL, + elfcpp::SHF_ALLOC, this->rel_dyn_, + ORDER_DYNAMIC_RELOCS, false); + } + return this->rel_dyn_; +} + +// Insn_template methods. + +// Return byte size of an instruction template. + +size_t +Insn_template::size() const +{ + switch (this->type()) + { + case THUMB16_TYPE: + case THUMB16_SPECIAL_TYPE: + return 2; + case ARM_TYPE: + case THUMB32_TYPE: + case DATA_TYPE: + return 4; + default: + gold_unreachable(); + } +} + +// Return alignment of an instruction template. + +unsigned +Insn_template::alignment() const +{ + switch (this->type()) + { + case THUMB16_TYPE: + case THUMB16_SPECIAL_TYPE: + case THUMB32_TYPE: + return 2; + case ARM_TYPE: + case DATA_TYPE: + return 4; + default: + gold_unreachable(); + } +} + +// Stub_template methods. + +Stub_template::Stub_template( + Stub_type type, const Insn_template* insns, + size_t insn_count) + : type_(type), insns_(insns), insn_count_(insn_count), alignment_(1), + entry_in_thumb_mode_(false), relocs_() +{ + off_t offset = 0; + + // Compute byte size and alignment of stub template. + for (size_t i = 0; i < insn_count; i++) + { + unsigned insn_alignment = insns[i].alignment(); + size_t insn_size = insns[i].size(); + gold_assert((offset & (insn_alignment - 1)) == 0); + this->alignment_ = std::max(this->alignment_, insn_alignment); + switch (insns[i].type()) + { + case Insn_template::THUMB16_TYPE: + case Insn_template::THUMB16_SPECIAL_TYPE: + if (i == 0) + this->entry_in_thumb_mode_ = true; + break; + + case Insn_template::THUMB32_TYPE: + 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; + + case Insn_template::ARM_TYPE: + // Handle cases where the target is encoded within the + // instruction. + if (insns[i].r_type() == elfcpp::R_ARM_JUMP24) + this->relocs_.push_back(Reloc(i, offset)); + break; + + case Insn_template::DATA_TYPE: + // Entry point cannot be data. + gold_assert(i != 0); + this->relocs_.push_back(Reloc(i, offset)); + break; + + default: + gold_unreachable(); + } + offset += insn_size; + } + this->size_ = offset; +} + +// Stub methods. + +// Template to implement do_write for a specific target endianness. + +template +void inline +Stub::do_fixed_endian_write(unsigned char* view, section_size_type view_size) +{ + const Stub_template* stub_template = this->stub_template(); + const Insn_template* insns = stub_template->insns(); + + // FIXME: We do not handle BE8 encoding yet. + unsigned char* pov = view; + for (size_t i = 0; i < stub_template->insn_count(); i++) + { + switch (insns[i].type()) + { + case Insn_template::THUMB16_TYPE: + elfcpp::Swap<16, big_endian>::writeval(pov, insns[i].data() & 0xffff); + break; + case Insn_template::THUMB16_SPECIAL_TYPE: + elfcpp::Swap<16, big_endian>::writeval( + pov, + this->thumb16_special(i)); + break; + case Insn_template::THUMB32_TYPE: + { + uint32_t hi = (insns[i].data() >> 16) & 0xffff; + uint32_t lo = insns[i].data() & 0xffff; + elfcpp::Swap<16, big_endian>::writeval(pov, hi); + elfcpp::Swap<16, big_endian>::writeval(pov + 2, lo); + } + break; + case Insn_template::ARM_TYPE: + case Insn_template::DATA_TYPE: + elfcpp::Swap<32, big_endian>::writeval(pov, insns[i].data()); + break; + default: + gold_unreachable(); + } + pov += insns[i].size(); + } + gold_assert(static_cast(pov - view) == view_size); +} + +// Reloc_stub::Key methods. + +// Dump a Key as a string for debugging. + +std::string +Reloc_stub::Key::name() const +{ + if (this->r_sym_ == invalid_index) + { + // Global symbol key name + // ::. + const std::string sym_name = this->u_.symbol->name(); + // We need to print two hex number and two colons. So just add 100 bytes + // to the symbol name size. + size_t len = sym_name.size() + 100; + char* buffer = new char[len]; + int c = snprintf(buffer, len, "%d:%s:%x", this->stub_type_, + sym_name.c_str(), this->addend_); + gold_assert(c > 0 && c < static_cast(len)); + delete[] buffer; + return std::string(buffer); + } + else + { + // local symbol key name + // :::. + const size_t len = 200; + char buffer[len]; + int c = snprintf(buffer, len, "%d:%p:%u:%x", this->stub_type_, + this->u_.relobj, this->r_sym_, this->addend_); + gold_assert(c > 0 && c < static_cast(len)); + return std::string(buffer); + } +} + +// Reloc_stub methods. + +// Determine the type of stub needed, if any, for a relocation of R_TYPE at +// LOCATION to DESTINATION. +// This code is based on the arm_type_of_stub function in +// bfd/elf32-arm.c. We have changed the interface a little to keep the Stub +// class simple. + +Stub_type +Reloc_stub::stub_type_for_reloc( + unsigned int r_type, + Arm_address location, + Arm_address destination, + bool target_is_thumb) +{ + Stub_type stub_type = arm_stub_none; + + // This is a bit ugly but we want to avoid using a templated class for + // big and little endianities. + bool may_use_blx; + bool should_force_pic_veneer; + bool thumb2; + bool thumb_only; + if (parameters->target().is_big_endian()) + { + const Target_arm* big_endian_target = + Target_arm::default_target(); + may_use_blx = big_endian_target->may_use_v5t_interworking(); + should_force_pic_veneer = big_endian_target->should_force_pic_veneer(); + thumb2 = big_endian_target->using_thumb2(); + thumb_only = big_endian_target->using_thumb_only(); + } + else + { + const Target_arm* little_endian_target = + Target_arm::default_target(); + may_use_blx = little_endian_target->may_use_v5t_interworking(); + should_force_pic_veneer = little_endian_target->should_force_pic_veneer(); + thumb2 = little_endian_target->using_thumb2(); + thumb_only = little_endian_target->using_thumb_only(); + } + + int64_t branch_offset; + bool output_is_position_independent = + parameters->options().output_is_position_independent(); + if (r_type == elfcpp::R_ARM_THM_CALL || r_type == elfcpp::R_ARM_THM_JUMP24) + { + // For THUMB BLX instruction, bit 1 of target comes from bit 1 of the + // base address (instruction address + 4). + 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(destination) - location; + + // Handle cases where: + // - this call goes too far (different Thumb/Thumb2 max + // distance) + // - it's a Thumb->Arm call and blx is not available, or it's a + // Thumb->Arm branch (not bl). A stub is needed in this case. + if ((!thumb2 + && (branch_offset > THM_MAX_FWD_BRANCH_OFFSET + || (branch_offset < THM_MAX_BWD_BRANCH_OFFSET))) + || (thumb2 + && (branch_offset > THM2_MAX_FWD_BRANCH_OFFSET + || (branch_offset < THM2_MAX_BWD_BRANCH_OFFSET))) + || ((!target_is_thumb) + && (((r_type == elfcpp::R_ARM_THM_CALL) && !may_use_blx) + || (r_type == elfcpp::R_ARM_THM_JUMP24)))) + { + if (target_is_thumb) + { + // Thumb to thumb. + if (!thumb_only) + { + stub_type = (output_is_position_independent + || should_force_pic_veneer) + // PIC stubs. + ? ((may_use_blx + && (r_type == elfcpp::R_ARM_THM_CALL)) + // V5T and above. Stub starts with ARM code, so + // we must be able to switch mode before + // reaching it, which is only possible for 'bl' + // (ie R_ARM_THM_CALL relocation). + ? arm_stub_long_branch_any_thumb_pic + // On V4T, use Thumb code only. + : arm_stub_long_branch_v4t_thumb_thumb_pic) + + // non-PIC stubs. + : ((may_use_blx + && (r_type == elfcpp::R_ARM_THM_CALL)) + ? arm_stub_long_branch_any_any // V5T and above. + : arm_stub_long_branch_v4t_thumb_thumb); // V4T. + } + else + { + stub_type = (output_is_position_independent + || should_force_pic_veneer) + ? arm_stub_long_branch_thumb_only_pic // PIC stub. + : arm_stub_long_branch_thumb_only; // non-PIC stub. + } + } + else + { + // Thumb to arm. + + // FIXME: We should check that the input section is from an + // object that has interwork enabled. + + stub_type = (output_is_position_independent + || should_force_pic_veneer) + // PIC stubs. + ? ((may_use_blx + && (r_type == elfcpp::R_ARM_THM_CALL)) + ? arm_stub_long_branch_any_arm_pic // V5T and above. + : arm_stub_long_branch_v4t_thumb_arm_pic) // V4T. + + // non-PIC stubs. + : ((may_use_blx + && (r_type == elfcpp::R_ARM_THM_CALL)) + ? arm_stub_long_branch_any_any // V5T and above. + : arm_stub_long_branch_v4t_thumb_arm); // V4T. + + // Handle v4t short branches. + if ((stub_type == arm_stub_long_branch_v4t_thumb_arm) + && (branch_offset <= THM_MAX_FWD_BRANCH_OFFSET) + && (branch_offset >= THM_MAX_BWD_BRANCH_OFFSET)) + stub_type = arm_stub_short_branch_v4t_thumb_arm; + } + } + } + else if (r_type == elfcpp::R_ARM_CALL + || r_type == elfcpp::R_ARM_JUMP24 + || r_type == elfcpp::R_ARM_PLT32) + { + branch_offset = static_cast(destination) - location; + if (target_is_thumb) + { + // Arm to thumb. + + // FIXME: We should check that the input section is from an + // object that has interwork enabled. + + // We have an extra 2-bytes reach because of + // the mode change (bit 24 (H) of BLX encoding). + if (branch_offset > (ARM_MAX_FWD_BRANCH_OFFSET + 2) + || (branch_offset < ARM_MAX_BWD_BRANCH_OFFSET) + || ((r_type == elfcpp::R_ARM_CALL) && !may_use_blx) + || (r_type == elfcpp::R_ARM_JUMP24) + || (r_type == elfcpp::R_ARM_PLT32)) + { + stub_type = (output_is_position_independent + || should_force_pic_veneer) + // PIC stubs. + ? (may_use_blx + ? arm_stub_long_branch_any_thumb_pic// V5T and above. + : arm_stub_long_branch_v4t_arm_thumb_pic) // V4T stub. + + // non-PIC stubs. + : (may_use_blx + ? arm_stub_long_branch_any_any // V5T and above. + : arm_stub_long_branch_v4t_arm_thumb); // V4T. + } + } + else + { + // Arm to arm. + if (branch_offset > ARM_MAX_FWD_BRANCH_OFFSET + || (branch_offset < ARM_MAX_BWD_BRANCH_OFFSET)) + { + stub_type = (output_is_position_independent + || should_force_pic_veneer) + ? arm_stub_long_branch_any_arm_pic // PIC stubs. + : arm_stub_long_branch_any_any; /// non-PIC. + } + } + } + + return stub_type; +} + +// Cortex_a8_stub methods. + +// Return the instruction for a THUMB16_SPECIAL_TYPE instruction template. +// I is the position of the instruction template in the stub template. + +uint16_t +Cortex_a8_stub::do_thumb16_special(size_t i) +{ + // The only use of this is to copy condition code from a conditional + // branch being worked around to the corresponding conditional branch in + // to the stub. + gold_assert(this->stub_template()->type() == arm_stub_a8_veneer_b_cond + && i == 0); + uint16_t data = this->stub_template()->insns()[i].data(); + gold_assert((data & 0xff00U) == 0xd000U); + data |= ((this->original_insn_ >> 22) & 0xf) << 8; + return data; +} + +// Stub_factory methods. + +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) + }; + + // V4T Arm -> Thumb long branch stub. Used on V4T where blx is not + // available. + static const Insn_template elf32_arm_stub_long_branch_v4t_arm_thumb[] = + { + Insn_template::arm_insn(0xe59fc000), // ldr ip, [pc, #0] + Insn_template::arm_insn(0xe12fff1c), // bx ip + Insn_template::data_word(0, elfcpp::R_ARM_ABS32, 0), + // dcd R_ARM_ABS32(X) + }; + + // Thumb -> Thumb long branch stub. Used on M-profile architectures. + static const Insn_template elf32_arm_stub_long_branch_thumb_only[] = + { + Insn_template::thumb16_insn(0xb401), // push {r0} + Insn_template::thumb16_insn(0x4802), // ldr r0, [pc, #8] + Insn_template::thumb16_insn(0x4684), // mov ip, r0 + Insn_template::thumb16_insn(0xbc01), // pop {r0} + 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) + }; + + // V4T Thumb -> Thumb long branch stub. Using the stack is not + // allowed. + static const Insn_template elf32_arm_stub_long_branch_v4t_thumb_thumb[] = + { + Insn_template::thumb16_insn(0x4778), // bx pc + Insn_template::thumb16_insn(0x46c0), // nop + 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) + }; + + // V4T Thumb -> ARM long branch stub. Used on V4T where blx is not + // available. + static const Insn_template elf32_arm_stub_long_branch_v4t_thumb_arm[] = + { + Insn_template::thumb16_insn(0x4778), // bx pc + 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) + }; + + // V4T Thumb -> ARM short branch stub. Shorter variant of the above + // one, when the destination is close enough. + static const Insn_template elf32_arm_stub_short_branch_v4t_thumb_arm[] = + { + Insn_template::thumb16_insn(0x4778), // bx pc + Insn_template::thumb16_insn(0x46c0), // nop + Insn_template::arm_rel_insn(0xea000000, -8), // b (X-8) + }; + + // ARM/Thumb -> ARM long branch stub, PIC. On V5T and above, use + // blx to reach the stub if necessary. + static const Insn_template elf32_arm_stub_long_branch_any_arm_pic[] = + { + Insn_template::arm_insn(0xe59fc000), // ldr r12, [pc] + Insn_template::arm_insn(0xe08ff00c), // add pc, pc, ip + Insn_template::data_word(0, elfcpp::R_ARM_REL32, -4), + // dcd R_ARM_REL32(X-4) + }; + + // 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 + // ARMv7). + static const Insn_template elf32_arm_stub_long_branch_any_thumb_pic[] = + { + Insn_template::arm_insn(0xe59fc004), // ldr r12, [pc, #4] + 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) + }; + + // V4T ARM -> ARM long branch stub, PIC. + static const Insn_template elf32_arm_stub_long_branch_v4t_arm_thumb_pic[] = + { + Insn_template::arm_insn(0xe59fc004), // ldr ip, [pc, #4] + 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) + }; + + // V4T Thumb -> ARM long branch stub, PIC. + static const Insn_template elf32_arm_stub_long_branch_v4t_thumb_arm_pic[] = + { + Insn_template::thumb16_insn(0x4778), // bx pc + Insn_template::thumb16_insn(0x46c0), // nop + 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) + }; + + // Thumb -> Thumb long branch stub, PIC. Used on M-profile + // architectures. + static const Insn_template elf32_arm_stub_long_branch_thumb_only_pic[] = + { + Insn_template::thumb16_insn(0xb401), // push {r0} + Insn_template::thumb16_insn(0x4802), // ldr r0, [pc, #8] + Insn_template::thumb16_insn(0x46fc), // mov ip, pc + Insn_template::thumb16_insn(0x4484), // add ip, r0 + 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) + }; + + // V4T Thumb -> Thumb long branch stub, PIC. Using the stack is not + // allowed. + static const Insn_template elf32_arm_stub_long_branch_v4t_thumb_thumb_pic[] = + { + Insn_template::thumb16_insn(0x4778), // bx pc + Insn_template::thumb16_insn(0x46c0), // nop + Insn_template::arm_insn(0xe59fc004), // ldr ip, [pc, #4] + 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) + }; + + // 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 X + // after: + // + static const Insn_template elf32_arm_stub_a8_veneer_b_cond[] = + { + Insn_template::thumb16_bcond_insn(0xd001), // b.n true + Insn_template::thumb32_b_insn(0xf000b800, -4), // b.w after + Insn_template::thumb32_b_insn(0xf000b800, -4) // true: + // 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. + static const Insn_template elf32_arm_stub_a8_veneer_blx[] = + { + Insn_template::arm_rel_insn(0xea000000, -8) // b dest + }; + + // Stub used to provide an interworking for R_ARM_V4BX relocation + // (bx r[n] instruction). + static const Insn_template elf32_arm_stub_v4_veneer_bx[] = + { + Insn_template::arm_insn(0xe3100001), // tst r, #1 + Insn_template::arm_insn(0x01a0f000), // moveq pc, r + Insn_template::arm_insn(0xe12fff10) // bx r + }; + + // Fill in the stub template look-up table. Stub templates are constructed + // per instance of Stub_factory for fast look-up without locking + // in a thread-enabled environment. + + this->stub_templates_[arm_stub_none] = + new Stub_template(arm_stub_none, NULL, 0); + +#define DEF_STUB(x) \ + do \ + { \ + size_t array_size \ + = sizeof(elf32_arm_stub_##x) / sizeof(elf32_arm_stub_##x[0]); \ + Stub_type type = arm_stub_##x; \ + this->stub_templates_[type] = \ + new Stub_template(type, elf32_arm_stub_##x, array_size); \ + } \ + while (0); + + DEF_STUBS +#undef DEF_STUB +} + +// Stub_table methods. + +// Remove all Cortex-A8 stub. + +template +void +Stub_table::remove_all_cortex_a8_stubs() +{ + for (Cortex_a8_stub_list::iterator p = this->cortex_a8_stubs_.begin(); + p != this->cortex_a8_stubs_.end(); + ++p) + delete p->second; + this->cortex_a8_stubs_.clear(); +} + +// Relocate one stub. This is a helper for Stub_table::relocate_stubs(). + +template +void +Stub_table::relocate_stub( + Stub* stub, + const Relocate_info<32, big_endian>* relinfo, + Target_arm* arm_target, + Output_section* output_section, + unsigned char* view, + Arm_address address, + section_size_type view_size) +{ + const Stub_template* stub_template = stub->stub_template(); + if (stub_template->reloc_count() != 0) + { + // Adjust view to cover the stub only. + section_size_type offset = stub->offset(); + section_size_type stub_size = stub_template->size(); + gold_assert(offset + stub_size <= view_size); + + arm_target->relocate_stub(stub, relinfo, output_section, view + offset, + address + offset, stub_size); + } +} + +// Relocate all stubs in this stub table. + +template +void +Stub_table::relocate_stubs( + const Relocate_info<32, big_endian>* relinfo, + Target_arm* arm_target, + Output_section* output_section, + unsigned char* view, + Arm_address address, + section_size_type view_size) +{ + // If we are passed a view bigger than the stub table's. we need to + // adjust the view. + gold_assert(address == this->address() + && (view_size + == static_cast(this->data_size()))); + + // Relocate all relocation stubs. + for (typename Reloc_stub_map::const_iterator p = this->reloc_stubs_.begin(); + p != this->reloc_stubs_.end(); + ++p) + this->relocate_stub(p->second, relinfo, arm_target, output_section, view, + address, view_size); + + // Relocate all Cortex-A8 stubs. + for (Cortex_a8_stub_list::iterator p = this->cortex_a8_stubs_.begin(); + p != this->cortex_a8_stubs_.end(); + ++p) + this->relocate_stub(p->second, relinfo, arm_target, output_section, view, + address, view_size); + + // Relocate all ARM V4BX stubs. + for (Arm_v4bx_stub_list::iterator p = this->arm_v4bx_stubs_.begin(); + p != this->arm_v4bx_stubs_.end(); + ++p) + { + if (*p != NULL) + this->relocate_stub(*p, relinfo, arm_target, output_section, view, + address, view_size); + } +} + +// Write out the stubs to file. + +template +void +Stub_table::do_write(Output_file* of) +{ + off_t offset = this->offset(); + const section_size_type oview_size = + convert_to_section_size_type(this->data_size()); + unsigned char* const oview = of->get_output_view(offset, oview_size); + + // Write relocation stubs. + for (typename Reloc_stub_map::const_iterator p = this->reloc_stubs_.begin(); + p != this->reloc_stubs_.end(); + ++p) + { + Reloc_stub* stub = p->second; + Arm_address address = this->address() + stub->offset(); + gold_assert(address + == align_address(address, + stub->stub_template()->alignment())); + stub->write(oview + stub->offset(), stub->stub_template()->size(), + big_endian); + } + + // Write Cortex-A8 stubs. + for (Cortex_a8_stub_list::const_iterator p = this->cortex_a8_stubs_.begin(); + p != this->cortex_a8_stubs_.end(); + ++p) + { + Cortex_a8_stub* stub = p->second; + Arm_address address = this->address() + stub->offset(); + gold_assert(address + == align_address(address, + stub->stub_template()->alignment())); + stub->write(oview + stub->offset(), stub->stub_template()->size(), + big_endian); + } + + // Write ARM V4BX relocation stubs. + for (Arm_v4bx_stub_list::const_iterator p = this->arm_v4bx_stubs_.begin(); + p != this->arm_v4bx_stubs_.end(); + ++p) + { + if (*p == NULL) + continue; + + Arm_address address = this->address() + (*p)->offset(); + gold_assert(address + == align_address(address, + (*p)->stub_template()->alignment())); + (*p)->write(oview + (*p)->offset(), (*p)->stub_template()->size(), + big_endian); + } + + of->write_output_view(this->offset(), oview_size, oview); +} + +// Update the data size and address alignment of the stub table at the end +// of a relaxation pass. Return true if either the data size or the +// alignment changed in this relaxation pass. + +template +bool +Stub_table::update_data_size_and_addralign() +{ + // Go over all stubs in table to compute data size and address alignment. + off_t size = this->reloc_stubs_size_; + unsigned addralign = this->reloc_stubs_addralign_; + + for (Cortex_a8_stub_list::const_iterator p = this->cortex_a8_stubs_.begin(); + p != this->cortex_a8_stubs_.end(); + ++p) + { + const Stub_template* stub_template = p->second->stub_template(); + addralign = std::max(addralign, stub_template->alignment()); + size = (align_address(size, stub_template->alignment()) + + stub_template->size()); + } + + for (Arm_v4bx_stub_list::const_iterator p = this->arm_v4bx_stubs_.begin(); + p != this->arm_v4bx_stubs_.end(); + ++p) + { + if (*p == NULL) + continue; + + const Stub_template* stub_template = (*p)->stub_template(); + addralign = std::max(addralign, stub_template->alignment()); + size = (align_address(size, stub_template->alignment()) + + stub_template->size()); + } + + // Check if either data size or alignment changed in this pass. + // 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; + + if (addralign != this->prev_addralign_) + changed = true; + this->prev_addralign_ = addralign; + + return changed; +} + +// Finalize the stubs. This sets the offsets of the stubs within the stub +// table. It also marks all input sections needing Cortex-A8 workaround. + +template +void +Stub_table::finalize_stubs() +{ + off_t off = this->reloc_stubs_size_; + for (Cortex_a8_stub_list::const_iterator p = this->cortex_a8_stubs_.begin(); + p != this->cortex_a8_stubs_.end(); + ++p) + { + Cortex_a8_stub* stub = p->second; + const Stub_template* stub_template = stub->stub_template(); + uint64_t stub_addralign = stub_template->alignment(); + off = align_address(off, stub_addralign); + stub->set_offset(off); + off += stub_template->size(); + + // Mark input section so that we can determine later if a code section + // needs the Cortex-A8 workaround quickly. + Arm_relobj* arm_relobj = + Arm_relobj::as_arm_relobj(stub->relobj()); + arm_relobj->mark_section_for_cortex_a8_workaround(stub->shndx()); + } + + for (Arm_v4bx_stub_list::const_iterator p = this->arm_v4bx_stubs_.begin(); + p != this->arm_v4bx_stubs_.end(); + ++p) + { + if (*p == NULL) + continue; + + const Stub_template* stub_template = (*p)->stub_template(); + uint64_t stub_addralign = stub_template->alignment(); + off = align_address(off, stub_addralign); + (*p)->set_offset(off); + off += stub_template->size(); + } + + gold_assert(off <= this->prev_data_size_); +} + +// Apply Cortex-A8 workaround to an address range between VIEW_ADDRESS +// and VIEW_ADDRESS + VIEW_SIZE - 1. VIEW points to the mapped address +// of the address range seen by the linker. + +template +void +Stub_table::apply_cortex_a8_workaround_to_address_range( + Target_arm* arm_target, + unsigned char* view, + Arm_address view_address, + section_size_type view_size) +{ + // Cortex-A8 stubs are sorted by addresses of branches being fixed up. + for (Cortex_a8_stub_list::const_iterator p = + this->cortex_a8_stubs_.lower_bound(view_address); + ((p != this->cortex_a8_stubs_.end()) + && (p->first < (view_address + view_size))); + ++p) + { + // We do not store the THUMB bit in the LSB of either the branch address + // or the stub offset. There is no need to strip the LSB. + Arm_address branch_address = p->first; + const Cortex_a8_stub* stub = p->second; + Arm_address stub_address = this->address() + stub->offset(); + + // Offset of the branch instruction relative to this view. + section_size_type offset = + convert_to_section_size_type(branch_address - view_address); + gold_assert((offset + 4) <= view_size); + + arm_target->apply_cortex_a8_workaround(stub, stub_address, + view + offset, branch_address); + } +} + +// Arm_input_section methods. + +// Initialize an Arm_input_section. + +template +void +Arm_input_section::init() +{ + Relobj* relobj = this->relobj(); + unsigned int shndx = this->shndx(); + + // We have to cache original size, alignment and contents to avoid locking + // the original file. + this->original_addralign_ = + convert_types(relobj->section_addralign(shndx)); + + // This is not efficient but we expect only a small number of relaxed + // input sections for stubs. + section_size_type section_size; + const unsigned char* section_contents = + relobj->section_contents(shndx, §ion_size, false); + this->original_size_ = + convert_types(relobj->section_size(shndx)); + + gold_assert(this->original_contents_ == NULL); + this->original_contents_ = new unsigned char[section_size]; + memcpy(this->original_contents_, section_contents, section_size); + + // We want to make this look like the original input section after + // output sections are finalized. + Output_section* os = relobj->output_section(shndx); + off_t offset = relobj->output_section_offset(shndx); + gold_assert(os != NULL && !relobj->is_output_section_offset_invalid(shndx)); + this->set_address(os->address() + offset); + this->set_file_offset(os->offset() + offset); + + this->set_current_data_size(this->original_size_); + this->finalize_data_size(); +} + +template +void +Arm_input_section::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_); + + // If this owns a stub table and it is not empty, write it. + if (this->is_stub_table_owner() && !this->stub_table_->empty()) + this->stub_table_->write(of); +} + +// Finalize data size. + +template +void +Arm_input_section::set_final_data_size() +{ + off_t off = convert_types(this->original_size_); + + if (this->is_stub_table_owner()) + { + this->stub_table_->finalize_data_size(); + off = align_address(off, this->stub_table_->addralign()); + off += this->stub_table_->data_size(); + } + this->set_data_size(off); +} + +// Reset address and file offset. + +template +void +Arm_input_section::do_reset_address_and_file_offset() +{ + // Size of the original input section contents. + off_t off = convert_types(this->original_size_); + + // If this is a stub table owner, account for the stub table size. + if (this->is_stub_table_owner()) + { + Stub_table* stub_table = this->stub_table_; + + // Reset the stub table's address and file offset. The + // current data size for child will be updated after that. + stub_table_->reset_address_and_file_offset(); + off = align_address(off, stub_table_->addralign()); + off += stub_table->current_data_size(); + } + + this->set_current_data_size(off); +} + +// Arm_exidx_cantunwind methods. + +// Write this to Output file OF for a fixed endianness. + +template +void +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); + + Output_section* os = this->relobj_->output_section(this->shndx_); + gold_assert(os != NULL); + + Arm_relobj* arm_relobj = + Arm_relobj::as_arm_relobj(this->relobj_); + Arm_address output_offset = + arm_relobj->get_output_section_offset(this->shndx_); + Arm_address section_start; + section_size_type section_size; + + // Find out the end of the text section referred by this. + if (output_offset != Arm_relobj::invalid_address) + { + section_start = os->address() + output_offset; + const Arm_exidx_input_section* exidx_input_section = + 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()); + } + else + { + // Currently this only happens for a relaxed section. + const Output_relaxed_input_section* poris = + os->find_relaxed_input_section(this->relobj_, this->shndx_); + gold_assert(poris != NULL); + section_start = poris->address(); + section_size = convert_to_section_size_type(poris->data_size()); + } + + // We always append this to the end of an EXIDX section. + Arm_address output_address = section_start + section_size; + + // Write out the entry. The first word either points to the beginning + // or after the end of a text section. The second word is the special + // EXIDX_CANTUNWIND value. + uint32_t prel31_offset = output_address - this->address(); + if (Bits<31>::has_overflow32(offset)) + gold_error(_("PREL31 overflow in EXIDX_CANTUNWIND entry")); + elfcpp::Swap_unaligned<32, big_endian>::writeval(oview, + prel31_offset & 0x7fffffffU); + elfcpp::Swap_unaligned<32, big_endian>::writeval(oview + 4, + elfcpp::EXIDX_CANTUNWIND); + + of->write_output_view(this->offset(), oview_size, oview); +} + +// Arm_exidx_merged_section methods. + +// Constructor for Arm_exidx_merged_section. +// EXIDX_INPUT_SECTION points to the unmodified EXIDX input section. +// SECTION_OFFSET_MAP points to a section offset map describing how +// parts of the input section are mapped to output. DELETED_BYTES is +// the number of bytes deleted from the EXIDX input section. + +Arm_exidx_merged_section::Arm_exidx_merged_section( + const Arm_exidx_input_section& exidx_input_section, + const Arm_exidx_section_offset_map& section_offset_map, + uint32_t deleted_bytes) + : Output_relaxed_input_section(exidx_input_section.relobj(), + exidx_input_section.shndx(), + exidx_input_section.addralign()), + exidx_input_section_(exidx_input_section), + section_offset_map_(section_offset_map) +{ + // If we retain or discard the whole EXIDX input section, we would + // not be here. + gold_assert(deleted_bytes != 0 + && deleted_bytes != this->exidx_input_section_.size()); + + // Fix size here so that we do not need to implement set_final_data_size. + uint32_t size = exidx_input_section.size() - deleted_bytes; + this->set_data_size(size); + this->fix_data_size(); + + // Allocate buffer for section contents and build contents. + this->section_contents_ = new unsigned char[size]; +} + +// Build the contents of a merged EXIDX output section. + +void +Arm_exidx_merged_section::build_contents( + const unsigned char* original_contents, + section_size_type original_size) +{ + // Go over spans of input offsets and write only those that are not + // discarded. + section_offset_type in_start = 0; + section_offset_type out_start = 0; + section_offset_type in_max = + convert_types(original_size); + section_offset_type out_max = + convert_types(this->data_size()); + for (Arm_exidx_section_offset_map::const_iterator p = + this->section_offset_map_.begin(); + p != this->section_offset_map_.end(); + ++p) + { + section_offset_type in_end = p->first; + gold_assert(in_end >= in_start); + section_offset_type out_end = p->second; + size_t in_chunk_size = convert_types(in_end - in_start + 1); + if (out_end != -1) + { + size_t out_chunk_size = + convert_types(out_end - out_start + 1); + + gold_assert(out_chunk_size == in_chunk_size + && in_end < in_max && out_end < out_max); + + memcpy(this->section_contents_ + out_start, + original_contents + in_start, + out_chunk_size); + out_start += out_chunk_size; + } + in_start += in_chunk_size; + } +} + +// Given an input OBJECT, an input section index SHNDX within that +// object, and an OFFSET relative to the start of that input +// section, return whether or not the corresponding offset within +// the output section is known. If this function returns true, it +// sets *POUTPUT to the output offset. The value -1 indicates that +// this input offset is being discarded. + +bool +Arm_exidx_merged_section::do_output_offset( + const Relobj* relobj, + unsigned int shndx, + section_offset_type offset, + section_offset_type* poutput) const +{ + // We only handle offsets for the original EXIDX input section. + if (relobj != this->exidx_input_section_.relobj() + || shndx != this->exidx_input_section_.shndx()) + return false; + + section_offset_type section_size = + convert_types(this->exidx_input_section_.size()); + if (offset < 0 || offset >= section_size) + // Input offset is out of valid range. + *poutput = -1; + else + { + // We need to look up the section offset map to determine the output + // offset. Find the reference point in map that is first offset + // bigger than or equal to this offset. + Arm_exidx_section_offset_map::const_iterator p = + this->section_offset_map_.lower_bound(offset); + + // The section offset maps are build such that this should not happen if + // input offset is in the valid range. + gold_assert(p != this->section_offset_map_.end()); + + // We need to check if this is dropped. + section_offset_type ref = p->first; + section_offset_type mapped_ref = p->second; + + if (mapped_ref != Arm_exidx_input_section::invalid_offset) + // Offset is present in output. + *poutput = mapped_ref + (offset - ref); + else + // Offset is discarded owing to EXIDX entry merging. + *poutput = -1; + } + + return true; +} + +// Write this to output file OF. + +void +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); + + memcpy(oview, this->section_contents_, oview_size); + of->write_output_view(this->offset(), oview_size, oview); +} + +// Arm_exidx_fixup methods. + +// Append an EXIDX_CANTUNWIND in the current output section if the last entry +// is not an EXIDX_CANTUNWIND entry already. The new EXIDX_CANTUNWIND entry +// points to the end of the last seen EXIDX section. + +void +Arm_exidx_fixup::add_exidx_cantunwind_as_needed() +{ + if (this->last_unwind_type_ != UT_EXIDX_CANTUNWIND + && this->last_input_section_ != NULL) + { + Relobj* relobj = this->last_input_section_->relobj(); + unsigned int text_shndx = this->last_input_section_->link(); + Arm_exidx_cantunwind* cantunwind = + new Arm_exidx_cantunwind(relobj, text_shndx); + this->exidx_output_section_->add_output_section_data(cantunwind); + this->last_unwind_type_ = UT_EXIDX_CANTUNWIND; + } +} + +// Process an EXIDX section entry in input. Return whether this entry +// can be deleted in the output. SECOND_WORD in the second word of the +// EXIDX entry. + +bool +Arm_exidx_fixup::process_exidx_entry(uint32_t second_word) +{ + bool delete_entry; + if (second_word == elfcpp::EXIDX_CANTUNWIND) + { + // Merge if previous entry is also an EXIDX_CANTUNWIND. + delete_entry = this->last_unwind_type_ == UT_EXIDX_CANTUNWIND; + this->last_unwind_type_ = UT_EXIDX_CANTUNWIND; + } + else if ((second_word & 0x80000000) != 0) + { + // Inlined unwinding data. Merge if equal to previous. + delete_entry = (merge_exidx_entries_ + && this->last_unwind_type_ == UT_INLINED_ENTRY + && this->last_inlined_entry_ == second_word); + this->last_unwind_type_ = UT_INLINED_ENTRY; + this->last_inlined_entry_ = second_word; + } + else + { + // Normal table entry. In theory we could merge these too, + // but duplicate entries are likely to be much less common. + delete_entry = false; + this->last_unwind_type_ = UT_NORMAL_ENTRY; + } + return delete_entry; +} + +// Update the current section offset map during EXIDX section fix-up. +// If there is no map, create one. INPUT_OFFSET is the offset of a +// reference point, DELETED_BYTES is the number of deleted by in the +// section so far. If DELETE_ENTRY is true, the reference point and +// all offsets after the previous reference point are discarded. + +void +Arm_exidx_fixup::update_offset_map( + section_offset_type input_offset, + section_size_type deleted_bytes, + bool delete_entry) +{ + if (this->section_offset_map_ == NULL) + this->section_offset_map_ = new Arm_exidx_section_offset_map(); + section_offset_type output_offset; + if (delete_entry) + output_offset = Arm_exidx_input_section::invalid_offset; + else + output_offset = input_offset - deleted_bytes; + (*this->section_offset_map_)[input_offset] = output_offset; +} + +// Process EXIDX_INPUT_SECTION for EXIDX entry merging. Return the number of +// bytes deleted. SECTION_CONTENTS points to the contents of the EXIDX +// section and SECTION_SIZE is the number of bytes pointed by SECTION_CONTENTS. +// If some entries are merged, also store a pointer to a newly created +// Arm_exidx_section_offset_map object in *PSECTION_OFFSET_MAP. The caller +// owns the map and is responsible for releasing it after use. + +template +uint32_t +Arm_exidx_fixup::process_exidx_section( + const Arm_exidx_input_section* exidx_input_section, + const unsigned char* section_contents, + section_size_type section_size, + Arm_exidx_section_offset_map** psection_offset_map) +{ + Relobj* relobj = exidx_input_section->relobj(); + unsigned shndx = exidx_input_section->shndx(); + + if ((section_size % 8) != 0) + { + // Something is wrong with this section. Better not touch it. + gold_error(_("uneven .ARM.exidx section size in %s section %u"), + relobj->name().c_str(), shndx); + this->last_input_section_ = exidx_input_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); + + for (section_size_type i = 0; i < section_size; i += 8) + { + typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype; + const Valtype* wv = + reinterpret_cast(section_contents + i + 4); + uint32_t second_word = elfcpp::Swap<32, big_endian>::readval(wv); + + bool delete_entry = this->process_exidx_entry(second_word); + + // Entry deletion causes changes in output offsets. We use a std::map + // to record these. And entry (x, y) means input offset x + // is mapped to output offset y. If y is invalid_offset, then x is + // dropped in the output. Because of the way std::map::lower_bound + // works, we record the last offset in a region w.r.t to keeping or + // dropping. If there is no entry (x0, y0) for an input offset x0, + // the output offset y0 of it is determined by the output offset y1 of + // the smallest input offset x1 > x0 that there is an (x1, y1) entry + // in the map. If y1 is not -1, then y0 = y1 + x0 - x1. Otherwise, y1 + // y0 is also -1. + if (delete_entry != prev_delete_entry && i != 0) + this->update_offset_map(i - 1, deleted_bytes, prev_delete_entry); + + // Update total deleted bytes for this entry. + if (delete_entry) + deleted_bytes += 8; + + 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) + update_offset_map(section_size - 1, deleted_bytes, prev_delete_entry); + + *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 + && deleted_bytes != section_size) + { + unsigned int link = exidx_input_section->link(); + Output_section* os = relobj->output_section(link); + gold_assert(os != NULL); + this->first_output_text_section_ = os; + } + + return deleted_bytes; +} + +// Arm_output_section methods. + +// Create a stub group for input sections from BEGIN to END. OWNER +// points to the input section to be the owner a new stub table. + +template +void +Arm_output_section::create_stub_group( + Input_section_list::const_iterator begin, + Input_section_list::const_iterator end, + Input_section_list::const_iterator owner, + Target_arm* target, + std::vector* new_relaxed_sections, + const Task* task) +{ + // 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. + 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* arm_input_section; + if (owner->is_relaxed_input_section()) + { + arm_input_section = + Arm_input_section::as_arm_input_section( + owner->relaxed_input_section()); + } + else + { + gold_assert(owner->is_input_section()); + // Create a new relaxed input section. We need to lock the original + // file. + Task_lock_obj tl(task, owner->relobj()); + arm_input_section = + target->new_arm_input_section(owner->relobj(), owner->shndx()); + new_relaxed_sections->push_back(arm_input_section); + } + + // Create a stub table. + Stub_table* stub_table = + 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; + + // Look for input sections or relaxed input sections in [begin ... end]. + do + { + if (p->is_input_section() || p->is_relaxed_input_section()) + { + // The stub table information for input sections live + // in their objects. + Arm_relobj* arm_relobj = + Arm_relobj::as_arm_relobj(p->relobj()); + arm_relobj->set_stub_table(p->shndx(), stub_table); + } + prev_p = p++; + } + while (prev_p != end); +} + +// Group input sections for stub generation. GROUP_SIZE is roughly the limit +// of stub groups. We grow a stub group by adding input section until the +// 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. + +template +void +Arm_output_section::group_sections( + section_size_type group_size, + bool stubs_always_after_branch, + Target_arm* target, + const Task* task) +{ + // States for grouping. + typedef enum + { + // No group is being built. + NO_GROUP, + // A group is being built but the stub table is not found yet. + // We keep group a stub group until the size is just under GROUP_SIZE. + // The last input section in the group will be used as the stub table. + FINDING_STUB_SECTION, + // A group is being built and we have already found a stub table. + // We enter this state to grow a stub group by adding input section + // after the stub table. This effectively doubles the group size. + HAS_STUB_SECTION + } State; + + // Any newly created relaxed sections are stored here. + std::vector new_relaxed_sections; + + State state = NO_GROUP; + section_size_type off = 0; + section_size_type group_begin_offset = 0; + section_size_type group_end_offset = 0; + section_size_type stub_table_end_offset = 0; + Input_section_list::const_iterator group_begin = + this->input_sections().end(); + Input_section_list::const_iterator stub_table = + this->input_sections().end(); + Input_section_list::const_iterator group_end = this->input_sections().end(); + for (Input_section_list::const_iterator p = this->input_sections().begin(); + p != this->input_sections().end(); + ++p) + { + section_size_type section_begin_offset = + align_address(off, p->addralign()); + section_size_type section_end_offset = + section_begin_offset + p->data_size(); + + // Check to see if we should group the previously seen sections. + switch (state) + { + case NO_GROUP: + break; + + case FINDING_STUB_SECTION: + // Adding this section makes the group larger than GROUP_SIZE. + 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, + task); + state = NO_GROUP; + } + else + { + // But wait, there's more! Input sections up to + // stub_group_size bytes after the stub table can be + // handled by it too. + state = HAS_STUB_SECTION; + stub_table = group_end; + stub_table_end_offset = group_end_offset; + } + } + break; + + case HAS_STUB_SECTION: + // Adding this section makes the post stub-section group larger + // than GROUP_SIZE. + if (section_end_offset - stub_table_end_offset >= group_size) + { + gold_assert(group_end != this->input_sections().end()); + this->create_stub_group(group_begin, group_end, stub_table, + target, &new_relaxed_sections, task); + state = NO_GROUP; + } + break; + + 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 + // instead of calling p->relobj()->section_size() to avoid locking. + if ((p->is_input_section() || p->is_relaxed_input_section()) + && (p->data_size() != 0)) + { + if (state == NO_GROUP) + { + state = FINDING_STUB_SECTION; + group_begin = p; + group_begin_offset = section_begin_offset; + } + + // Keep track of the last input section seen. + group_end = p; + group_end_offset = section_end_offset; + } + + off = section_end_offset; + } + + // Create a stub group for any ungrouped sections. + if (state == FINDING_STUB_SECTION || state == HAS_STUB_SECTION) + { + gold_assert(group_end != this->input_sections().end()); + this->create_stub_group(group_begin, group_end, + (state == FINDING_STUB_SECTION + ? group_end + : stub_table), + target, &new_relaxed_sections, task); + } + + // Convert input section into relaxed input section in a batch. + if (!new_relaxed_sections.empty()) + this->convert_input_sections_to_relaxed_sections(new_relaxed_sections); + + // Update the section offsets + for (size_t i = 0; i < new_relaxed_sections.size(); ++i) + { + Arm_relobj* arm_relobj = + Arm_relobj::as_arm_relobj( + new_relaxed_sections[i]->relobj()); + unsigned int shndx = new_relaxed_sections[i]->shndx(); + // Tell Arm_relobj that this input section is converted. + arm_relobj->convert_input_section_to_relaxed_section(shndx); + } +} + +// Append non empty text sections in this to LIST in ascending +// order of their position in this. + +template +void +Arm_output_section::append_text_sections_to_list( + Text_section_list* list) +{ + gold_assert((this->flags() & elfcpp::SHF_ALLOC) != 0); + + for (Input_section_list::const_iterator p = this->input_sections().begin(); + p != this->input_sections().end(); + ++p) + { + // We only care about plain or relaxed input sections. We also + // ignore any merged sections. + if (p->is_input_section() || p->is_relaxed_input_section()) + list->push_back(Text_section_list::value_type(p->relobj(), + p->shndx())); + } +} + +template +void +Arm_output_section::fix_exidx_coverage( + Layout* layout, + const Text_section_list& sorted_text_sections, + Symbol_table* symtab, + bool merge_exidx_entries, + const Task* task) +{ + // We should only do this for the EXIDX output section. + gold_assert(this->type() == elfcpp::SHT_ARM_EXIDX); + + // We don't want the relaxation loop to undo these changes, so we discard + // the current saved states and take another one after the fix-up. + this->discard_states(); + + // Remove all input sections. + uint64_t address = this->address(); + typedef std::list Input_section_list; + Input_section_list input_sections; + this->reset_address_and_file_offset(); + this->get_input_sections(address, std::string(""), &input_sections); + + 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_set; + typedef Unordered_map Text_to_exidx_map; + Text_to_exidx_map text_to_exidx_map; + for (Input_section_list::const_iterator p = input_sections.begin(); + p != input_sections.end(); + ++p) + { + // This should never happen. At this point, we should only see + // plain EXIDX input sections. + gold_assert(!p->is_relaxed_input_section()); + text_to_exidx_map[Section_id(p->relobj(), p->shndx())] = &(*p); + } + + Arm_exidx_fixup exidx_fixup(this, merge_exidx_entries); + + // Go over the sorted text sections. + typedef Unordered_set Section_id_set; + Section_id_set processed_input_sections; + for (Text_section_list::const_iterator p = sorted_text_sections.begin(); + p != sorted_text_sections.end(); + ++p) + { + Relobj* relobj = p->first; + unsigned int shndx = p->second; + + Arm_relobj* arm_relobj = + Arm_relobj::as_arm_relobj(relobj); + const Arm_exidx_input_section* exidx_input_section = + arm_relobj->exidx_input_section_by_link(shndx); + + // If this text section has no EXIDX section or if the EXIDX section + // has errors, force an EXIDX_CANTUNWIND entry pointing to the end + // of the last seen EXIDX section. + if (exidx_input_section == NULL || exidx_input_section->has_errors()) + { + exidx_fixup.add_exidx_cantunwind_as_needed(); + continue; + } + + Relobj* exidx_relobj = exidx_input_section->relobj(); + unsigned int exidx_shndx = exidx_input_section->shndx(); + Section_id sid(exidx_relobj, exidx_shndx); + Text_to_exidx_map::const_iterator iter = text_to_exidx_map.find(sid); + if (iter == text_to_exidx_map.end()) + { + // This is odd. We have not seen this EXIDX input section before. + // We cannot do fix-up. If we saw a SECTIONS clause in a script, + // issue a warning instead. We assume the user knows what he + // or she is doing. Otherwise, this is an error. + if (layout->script_options()->saw_sections_clause()) + gold_warning(_("unwinding may not work because EXIDX input section" + " %u of %s is not in EXIDX output section"), + exidx_shndx, exidx_relobj->name().c_str()); + else + gold_error(_("unwinding may not work because EXIDX input section" + " %u of %s is not in EXIDX output section"), + exidx_shndx, exidx_relobj->name().c_str()); + + exidx_fixup.add_exidx_cantunwind_as_needed(); + continue; + } + + // We need to access the contents of the EXIDX section, lock the + // object here. + Task_lock_obj tl(task, exidx_relobj); + section_size_type exidx_size; + const unsigned char* exidx_contents = + 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(exidx_input_section, + exidx_contents, + exidx_size, + §ion_offset_map); + + if (deleted_bytes == exidx_input_section->size()) + { + // The whole EXIDX section got merged. Remove it from output. + gold_assert(section_offset_map == NULL); + exidx_relobj->set_output_section(exidx_shndx, NULL); + + // All local symbols defined in this input section will be dropped. + // We need to adjust output local symbol count. + arm_relobj->set_output_local_symbol_count_needs_update(); + } + else if (deleted_bytes > 0) + { + // Some entries are merged. We need to convert this EXIDX input + // section into a relaxed section. + gold_assert(section_offset_map != NULL); + + Arm_exidx_merged_section* merged_section = + new Arm_exidx_merged_section(*exidx_input_section, + *section_offset_map, deleted_bytes); + merged_section->build_contents(exidx_contents, exidx_size); + + const std::string secname = exidx_relobj->section_name(exidx_shndx); + this->add_relaxed_input_section(layout, merged_section, secname); + arm_relobj->convert_input_section_to_relaxed_section(exidx_shndx); + + // All local symbols defined in discarded portions of this input + // section will be dropped. We need to adjust output local symbol + // count. + arm_relobj->set_output_local_symbol_count_needs_update(); + } + else + { + // Just add back the EXIDX input section. + gold_assert(section_offset_map == NULL); + const Output_section::Input_section* pis = iter->second; + gold_assert(pis->is_input_section()); + this->add_script_input_section(*pis); + } + + processed_input_sections.insert(Section_id(exidx_relobj, exidx_shndx)); + } + + // Insert an EXIDX_CANTUNWIND entry at the end of output if necessary. + exidx_fixup.add_exidx_cantunwind_as_needed(); + + // Remove any known EXIDX input sections that are not processed. + for (Input_section_list::const_iterator p = input_sections.begin(); + p != input_sections.end(); + ++p) + { + if (processed_input_sections.find(Section_id(p->relobj(), p->shndx())) + == processed_input_sections.end()) + { + // We discard a known EXIDX section because its linked + // text section has been folded by ICF. We also discard an + // EXIDX section with error, the output does not matter in this + // case. We do this to avoid triggering asserts. + Arm_relobj* arm_relobj = + Arm_relobj::as_arm_relobj(p->relobj()); + const Arm_exidx_input_section* exidx_input_section = + arm_relobj->exidx_input_section_by_shndx(p->shndx()); + gold_assert(exidx_input_section != NULL); + if (!exidx_input_section->has_errors()) + { + unsigned int text_shndx = exidx_input_section->link(); + gold_assert(symtab->is_section_folded(p->relobj(), text_shndx)); + } + + // Remove this from link. We also need to recount the + // local symbols. + p->relobj()->set_output_section(p->shndx(), NULL); + 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()); + this->set_entsize(8); + + // Make changes permanent. + this->save_states(); + this->set_section_offsets_need_adjustment(); +} + +// Link EXIDX output sections to text output sections. + +template +void +Arm_output_section::set_exidx_section_link() +{ + gold_assert(this->type() == elfcpp::SHT_ARM_EXIDX); + if (!this->input_sections().empty()) + { + Input_section_list::const_iterator p = this->input_sections().begin(); + Arm_relobj* arm_relobj = + Arm_relobj::as_arm_relobj(p->relobj()); + unsigned exidx_shndx = p->shndx(); + const Arm_exidx_input_section* exidx_input_section = + arm_relobj->exidx_input_section_by_shndx(exidx_shndx); + gold_assert(exidx_input_section != NULL); + unsigned int text_shndx = exidx_input_section->link(); + Output_section* os = arm_relobj->output_section(text_shndx); + this->set_link_section(os); + } +} + +// Arm_relobj methods. + +// Determine if an input section is scannable for stub processing. SHDR is +// the header of the section and SHNDX is the section index. OS is the output +// section for the input section and SYMTAB is the global symbol table used to +// look up ICF information. + +template +bool +Arm_relobj::section_is_scannable( + const elfcpp::Shdr<32, big_endian>& shdr, + unsigned int shndx, + const Output_section* os, + const Symbol_table* symtab) +{ + // Skip any empty sections, unallocated sections or sections whose + // type are not SHT_PROGBITS. + if (shdr.get_sh_size() == 0 + || (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0 + || shdr.get_sh_type() != elfcpp::SHT_PROGBITS) + return false; + + // Skip any discarded or ICF'ed sections. + if (os == NULL || symtab->is_section_folded(this, shndx)) + return false; + + // If this requires special offset handling, check to see if it is + // a relaxed section. If this is not, then it is a merged section that + // we cannot handle. + if (this->is_output_section_offset_invalid(shndx)) + { + const Output_relaxed_input_section* poris = + os->find_relaxed_input_section(this, shndx); + if (poris == NULL) + return false; + } + + return true; +} + +// Determine if we want to scan the SHNDX-th section for relocation stubs. +// This is a helper for Arm_relobj::scan_sections_for_stubs() below. + +template +bool +Arm_relobj::section_needs_reloc_stub_scanning( + const elfcpp::Shdr<32, big_endian>& shdr, + const Relobj::Output_sections& out_sections, + const Symbol_table* symtab, + const unsigned char* pshdrs) +{ + unsigned int sh_type = shdr.get_sh_type(); + if (sh_type != elfcpp::SHT_REL && sh_type != elfcpp::SHT_RELA) + return false; + + // Ignore empty section. + off_t sh_size = shdr.get_sh_size(); + if (sh_size == 0) + return false; + + // Ignore reloc section with unexpected symbol table. The + // error will be reported in the final link. + if (this->adjust_shndx(shdr.get_sh_link()) != this->symtab_shndx()) + return false; + + unsigned int reloc_size; + if (sh_type == elfcpp::SHT_REL) + reloc_size = elfcpp::Elf_sizes<32>::rel_size; + else + reloc_size = elfcpp::Elf_sizes<32>::rela_size; + + // Ignore reloc section with unexpected entsize or uneven size. + // The error will be reported in the final link. + if (reloc_size != shdr.get_sh_entsize() || sh_size % reloc_size != 0) + return false; + + // Ignore reloc section with bad info. This error will be + // reported in the final link. + unsigned int index = this->adjust_shndx(shdr.get_sh_info()); + if (index >= this->shnum()) + return false; + + const unsigned int shdr_size = elfcpp::Elf_sizes<32>::shdr_size; + const elfcpp::Shdr<32, big_endian> text_shdr(pshdrs + index * shdr_size); + return this->section_is_scannable(text_shdr, index, + out_sections[index], symtab); +} + +// Return the output address of either a plain input section or a relaxed +// input section. SHNDX is the section index. We define and use this +// instead of calling Output_section::output_address because that is slow +// for large output. + +template +Arm_address +Arm_relobj::simple_input_section_output_address( + unsigned int shndx, + Output_section* os) +{ + if (this->is_output_section_offset_invalid(shndx)) + { + const Output_relaxed_input_section* poris = + os->find_relaxed_input_section(this, shndx); + // We do not handle merged sections here. + gold_assert(poris != NULL); + return poris->address(); + } + else + return os->address() + this->get_output_section_offset(shndx); +} + +// Determine if we want to scan the SHNDX-th section for non-relocation stubs. +// This is a helper for Arm_relobj::scan_sections_for_stubs() below. + +template +bool +Arm_relobj::section_needs_cortex_a8_stub_scanning( + const elfcpp::Shdr<32, big_endian>& shdr, + unsigned int shndx, + Output_section* os, + const Symbol_table* symtab) +{ + if (!this->section_is_scannable(shdr, shndx, os, symtab)) + return false; + + // If the section does not cross any 4K-boundaries, it does not need to + // be scanned. + Arm_address address = this->simple_input_section_output_address(shndx, os); + if ((address & ~0xfffU) == ((address + shdr.get_sh_size() - 1) & ~0xfffU)) + return false; + + return true; +} + +// Scan a section for Cortex-A8 workaround. + +template +void +Arm_relobj::scan_section_for_cortex_a8_erratum( + const elfcpp::Shdr<32, big_endian>& shdr, + unsigned int shndx, + Output_section* os, + Target_arm* arm_target) +{ + // Look for the first mapping symbol in this section. It should be + // at (shndx, 0). + Mapping_symbol_position section_start(shndx, 0); + typename Mapping_symbols_info::const_iterator p = + this->mapping_symbols_info_.lower_bound(section_start); + + // There are no mapping symbols for this section. Treat it as a data-only + // section. Issue a warning if section is marked as containing + // instructions. + if (p == this->mapping_symbols_info_.end() || p->first.first != shndx) + { + if ((this->section_flags(shndx) & elfcpp::SHF_EXECINSTR) != 0) + gold_warning(_("cannot scan executable section %u of %s for Cortex-A8 " + "erratum because it has no mapping symbols."), + shndx, this->name().c_str()); + return; + } + + Arm_address output_address = + this->simple_input_section_output_address(shndx, os); + + // Get the section contents. + section_size_type input_view_size = 0; + const unsigned char* input_view = + this->section_contents(shndx, &input_view_size, false); + + // We need to go through the mapping symbols to determine what to + // 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) + { + typename Mapping_symbols_info::const_iterator next = + this->mapping_symbols_info_.upper_bound(p->first); + + // Only scan part of a section with THUMB code. + if (p->second == 't') + { + // Determine the end of this range. + section_size_type span_start = + convert_to_section_size_type(p->first.second); + section_size_type span_end; + if (next != this->mapping_symbols_info_.end() + && next->first.first == shndx) + span_end = convert_to_section_size_type(next->first.second); + else + span_end = convert_to_section_size_type(shdr.get_sh_size()); + + if (((span_start + output_address) & ~0xfffUL) + != ((span_end + output_address - 1) & ~0xfffUL)) + { + arm_target->scan_span_for_cortex_a8_erratum(this, shndx, + span_start, span_end, + input_view, + output_address); + } + } + + p = next; + } +} + +// Scan relocations for stub generation. + +template +void +Arm_relobj::scan_sections_for_stubs( + Target_arm* arm_target, + const Symbol_table* symtab, + const Layout* layout) +{ + unsigned int shnum = this->shnum(); + const unsigned int shdr_size = elfcpp::Elf_sizes<32>::shdr_size; + + // Read the section headers. + const unsigned char* pshdrs = this->get_view(this->elf_file()->shoff(), + shnum * shdr_size, + true, true); + + // To speed up processing, we set up hash tables for fast lookup of + // input offsets to output addresses. + this->initialize_input_to_output_maps(); + + const Relobj::Output_sections& out_sections(this->output_sections()); + + Relocate_info<32, big_endian> relinfo; + relinfo.symtab = symtab; + relinfo.layout = layout; + relinfo.object = this; + + // Do relocation stubs scanning. + const unsigned char* p = pshdrs + shdr_size; + for (unsigned int i = 1; i < shnum; ++i, p += shdr_size) + { + const elfcpp::Shdr<32, big_endian> shdr(p); + if (this->section_needs_reloc_stub_scanning(shdr, out_sections, symtab, + pshdrs)) + { + unsigned int index = this->adjust_shndx(shdr.get_sh_info()); + Arm_address output_offset = this->get_output_section_offset(index); + Arm_address output_address; + if (output_offset != invalid_address) + output_address = out_sections[index]->address() + output_offset; + else + { + // Currently this only happens for a relaxed section. + const Output_relaxed_input_section* poris = + out_sections[index]->find_relaxed_input_section(this, index); + gold_assert(poris != NULL); + output_address = poris->address(); + } + + // Get the relocations. + const unsigned char* prelocs = this->get_view(shdr.get_sh_offset(), + shdr.get_sh_size(), + true, false); + + // Get the section contents. This does work for the case in which + // we modify the contents of an input section. We need to pass the + // output view under such circumstances. + section_size_type input_view_size = 0; + const unsigned char* input_view = + this->section_contents(index, &input_view_size, false); + + relinfo.reloc_shndx = i; + relinfo.data_shndx = index; + unsigned int sh_type = shdr.get_sh_type(); + unsigned int reloc_size; + if (sh_type == elfcpp::SHT_REL) + reloc_size = elfcpp::Elf_sizes<32>::rel_size; + else + reloc_size = elfcpp::Elf_sizes<32>::rela_size; + + Output_section* os = out_sections[index]; + arm_target->scan_section_for_stubs(&relinfo, sh_type, prelocs, + shdr.get_sh_size() / reloc_size, + os, + output_offset == invalid_address, + input_view, output_address, + input_view_size); + } + } + + // Do Cortex-A8 erratum stubs scanning. This has to be done for a section + // after its relocation section, if there is one, is processed for + // relocation stubs. Merging this loop with the one above would have been + // complicated since we would have had to make sure that relocation stub + // scanning is done first. + if (arm_target->fix_cortex_a8()) + { + const unsigned char* p = pshdrs + shdr_size; + for (unsigned int i = 1; i < shnum; ++i, p += shdr_size) + { + const elfcpp::Shdr<32, big_endian> shdr(p); + if (this->section_needs_cortex_a8_stub_scanning(shdr, i, + out_sections[i], + symtab)) + this->scan_section_for_cortex_a8_erratum(shdr, i, out_sections[i], + arm_target); + } + } + + // After we've done the relocations, we release the hash tables, + // since we no longer need them. + this->free_input_to_output_maps(); +} + +// Count the local symbols. The ARM backend needs to know if a symbol +// is a THUMB function or not. For global symbols, it is easy because +// the Symbol object keeps the ELF symbol type. For local symbol it is +// harder because we cannot access this information. So we override the +// 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::do_count_local_symbols. + +template +void +Arm_relobj::do_count_local_symbols( + Stringpool_template* pool, + Stringpool_template* dynpool) +{ + // We need to fix-up the values of any local symbols whose type are + // STT_ARM_TFUNC. + + // Ask parent to count the local symbols. + Sized_relobj_file<32, big_endian>::do_count_local_symbols(pool, dynpool); + const unsigned int loccount = this->local_symbol_count(); + if (loccount == 0) + return; + + // Initialize the thumb function bit-vector. + std::vector empty_vector(loccount, false); + this->local_symbol_is_thumb_function_.swap(empty_vector); + + // Read the symbol table section header. + const unsigned int symtab_shndx = this->symtab_shndx(); + elfcpp::Shdr<32, big_endian> + symtabshdr(this, this->elf_file()->section_header(symtab_shndx)); + gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB); + + // Read the local symbols. + const int sym_size =elfcpp::Elf_sizes<32>::sym_size; + gold_assert(loccount == symtabshdr.get_sh_info()); + off_t locsize = loccount * sym_size; + const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(), + locsize, true, true); + + // For mapping symbol processing, we need to read the symbol names. + unsigned int strtab_shndx = this->adjust_shndx(symtabshdr.get_sh_link()); + if (strtab_shndx >= this->shnum()) + { + this->error(_("invalid symbol table name index: %u"), strtab_shndx); + return; + } + + elfcpp::Shdr<32, big_endian> + strtabshdr(this, this->elf_file()->section_header(strtab_shndx)); + if (strtabshdr.get_sh_type() != elfcpp::SHT_STRTAB) + { + this->error(_("symbol table name section has wrong type: %u"), + static_cast(strtabshdr.get_sh_type())); + return; + } + const char* pnames = + reinterpret_cast(this->get_view(strtabshdr.get_sh_offset(), + strtabshdr.get_sh_size(), + false, false)); + + // Loop over the local symbols and mark any local symbols pointing + // to THUMB functions. + + // Skip the first dummy symbol. + psyms += sym_size; + typename Sized_relobj_file<32, big_endian>::Local_values* plocal_values = + this->local_values(); + for (unsigned int i = 1; i < loccount; ++i, psyms += sym_size) + { + elfcpp::Sym<32, big_endian> sym(psyms); + elfcpp::STT st_type = sym.get_st_type(); + Symbol_value<32>& lv((*plocal_values)[i]); + Arm_address input_value = lv.input_value(); + + // Check to see if this is a mapping symbol. + const char* sym_name = pnames + sym.get_st_name(); + if (Target_arm::is_mapping_symbol_name(sym_name)) + { + bool is_ordinary; + unsigned int input_shndx = + this->adjust_sym_shndx(i, sym.get_st_shndx(), &is_ordinary); + gold_assert(is_ordinary); + + // Strip of LSB in case this is a THUMB symbol. + Mapping_symbol_position msp(input_shndx, input_value & ~1U); + this->mapping_symbols_info_[msp] = sym_name[1]; + } + + if (st_type == elfcpp::STT_ARM_TFUNC + || (st_type == elfcpp::STT_FUNC && ((input_value & 1) != 0))) + { + // This is a THUMB function. Mark this and canonicalize the + // symbol value by setting LSB. + this->local_symbol_is_thumb_function_[i] = true; + if ((input_value & 1) == 0) + lv.set_input_value(input_value | 1); + } + } +} + +// Relocate sections. +template +void +Arm_relobj::do_relocate_sections( + const Symbol_table* symtab, + const Layout* layout, + const unsigned char* pshdrs, + Output_file* of, + typename Sized_relobj_file<32, big_endian>::Views* pviews) +{ + // Call parent to relocate sections. + Sized_relobj_file<32, big_endian>::do_relocate_sections(symtab, layout, + pshdrs, of, pviews); + + // We do not generate stubs if doing a relocatable link. + if (parameters->options().relocatable()) + return; + + // Relocate stub tables. + unsigned int shnum = this->shnum(); + + Target_arm* arm_target = + Target_arm::default_target(); + + Relocate_info<32, big_endian> relinfo; + relinfo.symtab = symtab; + relinfo.layout = layout; + relinfo.object = this; + + for (unsigned int i = 1; i < shnum; ++i) + { + Arm_input_section* arm_input_section = + arm_target->find_arm_input_section(this, i); + + if (arm_input_section != NULL + && arm_input_section->is_stub_table_owner() + && !arm_input_section->stub_table()->empty()) + { + // We cannot discard a section if it owns a stub table. + Output_section* os = this->output_section(i); + gold_assert(os != NULL); + + relinfo.reloc_shndx = elfcpp::SHN_UNDEF; + relinfo.reloc_shdr = NULL; + relinfo.data_shndx = i; + relinfo.data_shdr = pshdrs + i * elfcpp::Elf_sizes<32>::shdr_size; + + gold_assert((*pviews)[i].view != NULL); + + // We are passed the output section view. Adjust it to cover the + // stub table only. + Stub_table* stub_table = arm_input_section->stub_table(); + gold_assert((stub_table->address() >= (*pviews)[i].address) + && ((stub_table->address() + stub_table->data_size()) + <= (*pviews)[i].address + (*pviews)[i].view_size)); + + off_t offset = stub_table->address() - (*pviews)[i].address; + 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); + } + + // Apply Cortex A8 workaround if applicable. + if (this->section_has_cortex_a8_workaround(i)) + { + unsigned char* view = (*pviews)[i].view; + Arm_address view_address = (*pviews)[i].address; + section_size_type view_size = (*pviews)[i].view_size; + Stub_table* stub_table = this->stub_tables_[i]; + + // Adjust view to cover section. + Output_section* os = this->output_section(i); + gold_assert(os != NULL); + Arm_address section_address = + this->simple_input_section_output_address(i, os); + uint64_t section_size = this->section_size(i); + + gold_assert(section_address >= view_address + && ((section_address + section_size) + <= (view_address + view_size))); + + unsigned char* section_view = view + (section_address - view_address); + + // Apply the Cortex-A8 workaround to the output address range + // corresponding to this input section. + stub_table->apply_cortex_a8_workaround_to_address_range( + arm_target, + section_view, + section_address, + section_size); + } + } +} + +// Find the linked text section of an EXIDX section by looking at the first +// relocation. 4.4.1 of the EHABI specifications says that an EXIDX section +// must be linked to its associated code section via the sh_link field of +// its section header. However, some tools are broken and the link is not +// always set. LD just drops such an EXIDX section silently, causing the +// associated code not unwindabled. Here we try a little bit harder to +// discover the linked code section. +// +// PSHDR points to the section header of a relocation section of an EXIDX +// section. If we can find a linked text section, return true and +// store the text section index in the location PSHNDX. Otherwise +// return false. + +template +bool +Arm_relobj::find_linked_text_section( + const unsigned char* pshdr, + const unsigned char* psyms, + 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) + reloc_size = elfcpp::Elf_sizes<32>::rel_size; + 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); + + // 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) + { + Arm_address r_offset; + typename elfcpp::Elf_types<32>::Elf_WXword r_info; + if (shdr.get_sh_type() == elfcpp::SHT_REL) + { + typename elfcpp::Rel<32, big_endian> reloc(prelocs); + r_info = reloc.get_r_info(); + r_offset = reloc.get_r_offset(); + } + else + { + typename elfcpp::Rela<32, big_endian> reloc(prelocs); + r_info = reloc.get_r_info(); + r_offset = reloc.get_r_offset(); + } + + unsigned int r_type = elfcpp::elf_r_type<32>(r_info); + if (r_type != elfcpp::R_ARM_PREL31 && r_type != elfcpp::R_ARM_SBREL31) + continue; + + unsigned int r_sym = elfcpp::elf_r_sym<32>(r_info); + if (r_sym == 0 + || r_sym >= this->local_symbol_count() + || r_offset != 0) + continue; + + // This is the relocation for the first word of the first EXIDX entry. + // We expect to see a local section symbol. + const int sym_size = elfcpp::Elf_sizes<32>::sym_size; + elfcpp::Sym<32, big_endian> sym(psyms + r_sym * sym_size); + if (sym.get_st_type() == elfcpp::STT_SECTION) + { + bool is_ordinary; + *pshndx = + this->adjust_sym_shndx(r_sym, sym.get_st_shndx(), &is_ordinary); + gold_assert(is_ordinary); + return true; + } + else + return false; + } + + return false; +} + +// Make an EXIDX input section object for an EXIDX section whose index is +// SHNDX. SHDR is the section header of the EXIDX section and TEXT_SHNDX +// is the section index of the linked text section. + +template +void +Arm_relobj::make_exidx_input_section( + unsigned int shndx, + const elfcpp::Shdr<32, big_endian>& shdr, + unsigned int text_shndx, + const elfcpp::Shdr<32, big_endian>& text_shdr) +{ + // Create an Arm_exidx_input_section object for this EXIDX section. + Arm_exidx_input_section* exidx_input_section = + new Arm_exidx_input_section(this, shndx, text_shndx, shdr.get_sh_size(), + shdr.get_sh_addralign(), + text_shdr.get_sh_size()); + + gold_assert(this->exidx_section_map_[shndx] == NULL); + this->exidx_section_map_[shndx] = exidx_input_section; + + if (text_shndx == elfcpp::SHN_UNDEF || text_shndx >= this->shnum()) + { + gold_error(_("EXIDX section %s(%u) links to invalid section %u in %s"), + 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 = + this->exidx_section_map_[text_shndx]->shndx(); + gold_error(_("EXIDX sections %s(%u) and %s(%u) both link to text section" + "%s(%u) in %s"), + this->section_name(shndx).c_str(), shndx, + this->section_name(other_exidx_shndx).c_str(), + other_exidx_shndx, this->section_name(text_shndx).c_str(), + text_shndx, this->name().c_str()); + exidx_input_section->set_has_errors(); + } + else + this->exidx_section_map_[text_shndx] = exidx_input_section; + + // Check section flags of text section. + if ((text_shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0) + { + gold_error(_("EXIDX section %s(%u) links to non-allocated section %s(%u) " + " in %s"), + this->section_name(shndx).c_str(), shndx, + this->section_name(text_shndx).c_str(), text_shndx, + this->name().c_str()); + exidx_input_section->set_has_errors(); + } + else if ((text_shdr.get_sh_flags() & elfcpp::SHF_EXECINSTR) == 0) + // I would like to make this an error but currently ld just ignores + // this. + gold_warning(_("EXIDX section %s(%u) links to non-executable section " + "%s(%u) in %s"), + this->section_name(shndx).c_str(), shndx, + this->section_name(text_shndx).c_str(), text_shndx, + this->name().c_str()); +} + +// Read the symbol information. + +template +void +Arm_relobj::do_read_symbols(Read_symbols_data* sd) +{ + // Call parent class to read symbol information. + Sized_relobj_file<32, big_endian>::do_read_symbols(sd); + + // If this input file is a binary file, it has no processor + // specific flags and attributes section. + Input_file::Format format = this->input_file()->format(); + if (format != Input_file::FORMAT_ELF) + { + gold_assert(format == Input_file::FORMAT_BINARY); + this->merge_flags_and_attributes_ = false; + return; + } + + // Read processor-specific flags in ELF file header. + const unsigned char* pehdr = this->get_view(elfcpp::file_header_offset, + elfcpp::Elf_sizes<32>::ehdr_size, + true, false); + elfcpp::Ehdr<32, big_endian> ehdr(pehdr); + this->processor_specific_flags_ = ehdr.get_e_flags(); + + // Go over the section headers and look for .ARM.attributes and .ARM.exidx + // sections. + std::vector deferred_exidx_sections; + const size_t shdr_size = elfcpp::Elf_sizes<32>::shdr_size; + const unsigned char* pshdrs = sd->section_headers->data(); + const unsigned char* ps = pshdrs + shdr_size; + bool must_merge_flags_and_attributes = false; + for (unsigned int i = 1; i < this->shnum(); ++i, ps += shdr_size) + { + elfcpp::Shdr<32, big_endian> shdr(ps); + + // Sometimes an object has no contents except the section name string + // table and an empty symbol table with the undefined symbol. We + // don't want to merge processor-specific flags from such an object. + if (shdr.get_sh_type() == elfcpp::SHT_SYMTAB) + { + // Symbol table is not empty. + const elfcpp::Elf_types<32>::Elf_WXword sym_size = + elfcpp::Elf_sizes<32>::sym_size; + if (shdr.get_sh_size() > sym_size) + must_merge_flags_and_attributes = true; + } + else if (shdr.get_sh_type() != elfcpp::SHT_STRTAB) + // If this is neither an empty symbol table nor a string table, + // be conservative. + must_merge_flags_and_attributes = true; + + if (shdr.get_sh_type() == elfcpp::SHT_ARM_ATTRIBUTES) + { + 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()); + const unsigned char* view = + this->get_view(section_offset, section_size, true, false); + this->attributes_section_data_ = + new Attributes_section_data(view, section_size); + } + else if (shdr.get_sh_type() == elfcpp::SHT_ARM_EXIDX) + { + unsigned int text_shndx = this->adjust_shndx(shdr.get_sh_link()); + if (text_shndx == elfcpp::SHN_UNDEF) + deferred_exidx_sections.push_back(i); + else + { + elfcpp::Shdr<32, big_endian> text_shdr(pshdrs + + text_shndx * shdr_size); + this->make_exidx_input_section(i, shdr, text_shndx, text_shdr); + } + // EHABI 4.4.1 requires that SHF_LINK_ORDER flag to be set. + if ((shdr.get_sh_flags() & elfcpp::SHF_LINK_ORDER) == 0) + gold_warning(_("SHF_LINK_ORDER not set in EXIDX section %s of %s"), + this->section_name(i).c_str(), this->name().c_str()); + } + } + + // This is rare. + if (!must_merge_flags_and_attributes) + { + gold_assert(deferred_exidx_sections.empty()); + this->merge_flags_and_attributes_ = false; + return; + } + + // 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()) + { + // We need to go over the section headers again to find the mapping + // from sections being relocated to their relocation sections. This is + // a bit inefficient as we could do that in the loop above. However, + // we do not expect any deferred EXIDX sections normally. So we do not + // want to slow down the most common path. + typedef Unordered_map Reloc_map; + Reloc_map reloc_map; + ps = pshdrs + shdr_size; + for (unsigned int i = 1; i < this->shnum(); ++i, ps += shdr_size) + { + elfcpp::Shdr<32, big_endian> shdr(ps); + elfcpp::Elf_Word sh_type = shdr.get_sh_type(); + if (sh_type == elfcpp::SHT_REL || sh_type == elfcpp::SHT_RELA) + { + unsigned int info_shndx = this->adjust_shndx(shdr.get_sh_info()); + if (info_shndx >= this->shnum()) + gold_error(_("relocation section %u has invalid info %u"), + i, info_shndx); + Reloc_map::value_type value(info_shndx, i); + std::pair result = + reloc_map.insert(value); + if (!result.second) + gold_error(_("section %u has multiple relocation sections " + "%u and %u"), + info_shndx, i, reloc_map[info_shndx]); + } + } + + // Read the symbol table section header. + const unsigned int symtab_shndx = this->symtab_shndx(); + elfcpp::Shdr<32, big_endian> + symtabshdr(this, this->elf_file()->section_header(symtab_shndx)); + gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB); + + // Read the local symbols. + const int sym_size =elfcpp::Elf_sizes<32>::sym_size; + const unsigned int loccount = this->local_symbol_count(); + gold_assert(loccount == symtabshdr.get_sh_info()); + off_t locsize = loccount * sym_size; + const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(), + locsize, true, true); + + // Process the deferred EXIDX sections. + for (unsigned int i = 0; i < deferred_exidx_sections.size(); ++i) + { + unsigned int shndx = deferred_exidx_sections[i]; + elfcpp::Shdr<32, big_endian> shdr(pshdrs + shndx * shdr_size); + unsigned int text_shndx = elfcpp::SHN_UNDEF; + Reloc_map::const_iterator it = reloc_map.find(shndx); + if (it != reloc_map.end()) + find_linked_text_section(pshdrs + it->second * shdr_size, + psyms, &text_shndx); + elfcpp::Shdr<32, big_endian> text_shdr(pshdrs + + text_shndx * shdr_size); + this->make_exidx_input_section(shndx, shdr, text_shndx, text_shdr); + } + } +} + +// Process relocations for garbage collection. The ARM target uses .ARM.exidx +// 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 +// in the base class to handle these implicit references. + +template +void +Arm_relobj::do_gc_process_relocs(Symbol_table* symtab, + Layout* layout, + Read_relocs_data* rd) +{ + // First, call base class method to process relocations in this object. + Sized_relobj_file<32, big_endian>::do_gc_process_relocs(symtab, layout, rd); + + // If --gc-sections is not specified, there is nothing more to do. + // 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(), + shnum * shdr_size, + true, true); + + // Scan section headers for sections of type SHT_ARM_EXIDX. Add references + // to these from the linked text sections. + const unsigned char* ps = pshdrs + shdr_size; + for (unsigned int i = 1; i < shnum; ++i, ps += shdr_size) + { + elfcpp::Shdr<32, big_endian> shdr(ps); + if (shdr.get_sh_type() == elfcpp::SHT_ARM_EXIDX) + { + // Found an .ARM.exidx section, add it to the set of reachable + // sections from its linked text section. + unsigned int text_shndx = this->adjust_shndx(shdr.get_sh_link()); + symtab->gc()->add_reference(this, text_shndx, this, i); + } + } +} + +// Update output local symbol count. Owing to EXIDX entry merging, some local +// symbols will be removed in output. Adjust output local symbol count +// accordingly. We can only changed the static output local symbol count. It +// is too late to change the dynamic symbols. + +template +void +Arm_relobj::update_output_local_symbol_count() +{ + // Caller should check that this needs updating. We want caller checking + // because output_local_symbol_count_needs_update() is most likely inlined. + gold_assert(this->output_local_symbol_count_needs_update_); + + gold_assert(this->symtab_shndx() != -1U); + if (this->symtab_shndx() == 0) + { + // This object has no symbols. Weird but legal. + return; + } + + // Read the symbol table section header. + const unsigned int symtab_shndx = this->symtab_shndx(); + elfcpp::Shdr<32, big_endian> + symtabshdr(this, this->elf_file()->section_header(symtab_shndx)); + gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB); + + // Read the local symbols. + const int sym_size = elfcpp::Elf_sizes<32>::sym_size; + const unsigned int loccount = this->local_symbol_count(); + gold_assert(loccount == symtabshdr.get_sh_info()); + off_t locsize = loccount * sym_size; + const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(), + locsize, true, true); + + // Loop over the local symbols. + + typedef typename Sized_relobj_file<32, big_endian>::Output_sections + Output_sections; + const Output_sections& out_sections(this->output_sections()); + unsigned int shnum = this->shnum(); + unsigned int count = 0; + // Skip the first, dummy, symbol. + psyms += sym_size; + for (unsigned int i = 1; i < loccount; ++i, psyms += sym_size) + { + elfcpp::Sym<32, big_endian> sym(psyms); + + Symbol_value<32>& lv((*this->local_values())[i]); + + // This local symbol was already discarded by do_count_local_symbols. + if (lv.is_output_symtab_index_set() && !lv.has_output_symtab_entry()) + continue; + + bool is_ordinary; + unsigned int shndx = this->adjust_sym_shndx(i, sym.get_st_shndx(), + &is_ordinary); + + if (shndx < shnum) + { + Output_section* os = out_sections[shndx]; + + // This local symbol no longer has an output section. Discard it. + if (os == NULL) + { + lv.set_no_output_symtab_entry(); + continue; + } + + // Currently we only discard parts of EXIDX input sections. + // We explicitly check for a merged EXIDX input section to avoid + // calling Output_section_data::output_offset unless necessary. + if ((this->get_output_section_offset(shndx) == invalid_address) + && (this->exidx_input_section_by_shndx(shndx) != NULL)) + { + section_offset_type output_offset = + os->output_offset(this, shndx, lv.input_value()); + if (output_offset == -1) + { + // This symbol is defined in a part of an EXIDX input section + // that is discarded due to entry merging. + lv.set_no_output_symtab_entry(); + continue; + } + } + } + + ++count; + } + + this->set_output_local_symbol_count(count); + this->output_local_symbol_count_needs_update_ = false; +} + +// Arm_dynobj methods. + +// Read the symbol information. + +template +void +Arm_dynobj::do_read_symbols(Read_symbols_data* sd) +{ + // Call parent class to read symbol information. + Sized_dynobj<32, big_endian>::do_read_symbols(sd); + + // Read processor-specific flags in ELF file header. + const unsigned char* pehdr = this->get_view(elfcpp::file_header_offset, + elfcpp::Elf_sizes<32>::ehdr_size, + true, false); + elfcpp::Ehdr<32, big_endian> ehdr(pehdr); + this->processor_specific_flags_ = ehdr.get_e_flags(); + + // Read the attributes section if there is one. + // We read from the end because gas seems to put it near the end of + // the section headers. + const size_t shdr_size = elfcpp::Elf_sizes<32>::shdr_size; + const unsigned char* ps = + sd->section_headers->data() + shdr_size * (this->shnum() - 1); + for (unsigned int i = this->shnum(); i > 0; --i, ps -= shdr_size) + { + elfcpp::Shdr<32, big_endian> shdr(ps); + if (shdr.get_sh_type() == elfcpp::SHT_ARM_ATTRIBUTES) + { + section_offset_type section_offset = shdr.get_sh_offset(); + section_size_type section_size = + convert_to_section_size_type(shdr.get_sh_size()); + const unsigned char* view = + this->get_view(section_offset, section_size, true, false); + this->attributes_section_data_ = + new Attributes_section_data(view, section_size); + break; + } + } +} + +// Stub_addend_reader methods. + +// Read the addend of a REL relocation of type R_TYPE at VIEW. + +template +elfcpp::Elf_types<32>::Elf_Swxword +Stub_addend_reader::operator()( + unsigned int r_type, + const unsigned char* view, + const typename Reloc_types::Reloc&) const +{ + typedef class Arm_relocate_functions RelocFuncs; + + switch (r_type) + { + case elfcpp::R_ARM_CALL: + case elfcpp::R_ARM_JUMP24: + case elfcpp::R_ARM_PLT32: + { + typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype; + const Valtype* wv = reinterpret_cast(view); + Valtype val = elfcpp::Swap<32, big_endian>::readval(wv); + return Bits<26>::sign_extend32(val << 2); + } + + case elfcpp::R_ARM_THM_CALL: + case elfcpp::R_ARM_THM_JUMP24: + case elfcpp::R_ARM_THM_XPC22: + { + typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype; + const Valtype* wv = reinterpret_cast(view); + Valtype upper_insn = elfcpp::Swap<16, big_endian>::readval(wv); + Valtype lower_insn = elfcpp::Swap<16, big_endian>::readval(wv + 1); + return RelocFuncs::thumb32_branch_offset(upper_insn, lower_insn); + } + + case elfcpp::R_ARM_THM_JUMP19: + { + typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype; + const Valtype* wv = reinterpret_cast(view); + Valtype upper_insn = elfcpp::Swap<16, big_endian>::readval(wv); + Valtype lower_insn = elfcpp::Swap<16, big_endian>::readval(wv + 1); + return RelocFuncs::thumb32_cond_branch_offset(upper_insn, lower_insn); + } + + default: + gold_unreachable(); + } +} + +// Arm_output_data_got methods. + +// Add a GOT pair for R_ARM_TLS_GD32. The creates a pair of GOT entries. +// The first one is initialized to be 1, which is the module index for +// the main executable and the second one 0. A reloc of the type +// R_ARM_TLS_DTPOFF32 will be created for the second GOT entry and will +// be applied by gold. GSYM is a global symbol. +// +template +void +Arm_output_data_got::add_tls_gd32_with_static_reloc( + unsigned int got_type, + Symbol* gsym) +{ + if (gsym->has_got_offset(got_type)) + return; + + // 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); + got_offset = this->add_constant(0); + this->static_relocs_.push_back(Static_reloc(got_offset, + elfcpp::R_ARM_TLS_DTPOFF32, + gsym)); +} + +// Same as the above but for a local symbol. + +template +void +Arm_output_data_got::add_tls_gd32_with_static_reloc( + unsigned int got_type, + Sized_relobj_file<32, big_endian>* object, + unsigned int index) +{ + if (object->local_has_got_offset(index, got_type)) + return; + + // We are doing a static link. Just mark it as belong to module 1, + // the executable. + 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, + object, index)); +} + +template +void +Arm_output_data_got::do_write(Output_file* of) +{ + // Call parent to write out GOT. + Output_data_got<32, big_endian>::do_write(of); + + // We are done if there is no fix up. + if (this->static_relocs_.empty()) + return; + + gold_assert(parameters->doing_static_link()); + + const off_t offset = this->offset(); + const section_size_type oview_size = + convert_to_section_size_type(this->data_size()); + unsigned char* const oview = of->get_output_view(offset, oview_size); + + 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 = + align_address(ARM_TCB_SIZE, tls_segment->maximum_alignment()); + + 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()) + { + Sized_relobj_file<32, big_endian>* object = reloc.relobj(); + const Symbol_value<32>* psymval = + reloc.relobj()->local_symbol(reloc.index()); + + // We are doing static linking. Issue an error and skip this + // relocation if the symbol is undefined or in a discarded_section. + bool is_ordinary; + unsigned int shndx = psymval->input_shndx(&is_ordinary); + if ((shndx == elfcpp::SHN_UNDEF) + || (is_ordinary + && shndx != elfcpp::SHN_UNDEF + && !object->is_section_included(shndx) + && !this->symbol_table_->is_section_folded(object, shndx))) + { + gold_error(_("undefined or discarded local symbol %u from " + " object %s in GOT"), + reloc.index(), reloc.relobj()->name().c_str()); + continue; + } + + value = psymval->value(object, 0); + } + else + { + const Symbol* gsym = reloc.symbol(); + gold_assert(gsym != NULL); + if (gsym->is_forwarder()) + gsym = this->symbol_table_->resolve_forwards(gsym); + + // We are doing static linking. Issue an error and skip this + // relocation if the symbol is undefined or in a discarded_section + // unless it is a weakly_undefined symbol. + if ((gsym->is_defined_in_discarded_section() + || gsym->is_undefined()) + && !gsym->is_weak_undefined()) + { + gold_error(_("undefined or discarded symbol %s in GOT"), + gsym->name()); + continue; + } + + if (!gsym->is_weak_undefined()) + { + const Sized_symbol<32>* sym = + static_cast*>(gsym); + value = sym->value(); + } + else + value = 0; + } + + unsigned got_offset = reloc.got_offset(); + gold_assert(got_offset < oview_size); + + typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype; + Valtype* wv = reinterpret_cast(oview + got_offset); + Valtype x; + switch (reloc.r_type()) + { + case elfcpp::R_ARM_TLS_DTPOFF32: + x = value; + break; + case elfcpp::R_ARM_TLS_TPOFF32: + x = value + aligned_tcb_size; + break; + default: + gold_unreachable(); + } + elfcpp::Swap<32, big_endian>::writeval(wv, x); + } + + of->write_output_view(offset, oview_size, oview); +} + +// 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 +class Output_data_plt_arm : public Output_section_data +{ + public: + typedef Output_data_reloc + Reloc_section; + + Output_data_plt_arm(Layout*, uint64_t addralign, Output_data_space*); + + // Add an entry to the PLT. + void + add_entry(Symbol* gsym); + + // Return the .rel.plt section data. + const Reloc_section* + rel_plt() const + { return this->rel_; } + + // Return the number of PLT entries. + unsigned int + entry_count() const + { return this->count_; } + + // Return the offset of the first non-reserved PLT entry. + unsigned int + first_plt_entry_offset() const + { return this->do_first_plt_entry_offset(); } + + // Return the size of a 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); + + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _("** PLT")); } + + private: + // Set the final size. + void + set_final_data_size() + { + this->set_data_size(this->first_plt_entry_offset() + + this->count_ * this->get_plt_entry_size()); + } + + // Write out the PLT data. + void + do_write(Output_file*); + + // The reloc section. + Reloc_section* rel_; + // The .got.plt section. + Output_data_space* got_plt_; + // The number of PLT entries. + unsigned int count_; +}; + +// Create the PLT section. The ordinary .got section is an argument, +// since we need to refer to the start. We also create our own .got +// section just for PLT entries. + +template +Output_data_plt_arm::Output_data_plt_arm(Layout* layout, + uint64_t addralign, + Output_data_space* got_plt) + : 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, + elfcpp::SHF_ALLOC, this->rel_, + ORDER_DYNAMIC_PLT_RELOCS, false); +} + +template +void +Output_data_plt_arm::do_adjust_output_section(Output_section* os) +{ + os->set_entsize(0); +} + +// Add an entry to the PLT. + +template +void +Output_data_plt_arm::add_entry(Symbol* gsym) +{ + gold_assert(!gsym->has_plt_offset()); + + // Note that when setting the PLT offset we skip the initial + // reserved PLT entry. + gsym->set_plt_offset((this->count_) * this->get_plt_entry_size() + + this->first_plt_entry_offset()); + + ++this->count_; + + section_offset_type got_offset = this->got_plt_->current_data_size(); + + // Every PLT entry needs a GOT entry which points back to the PLT + // entry (this will be changed by the dynamic linker, normally + // lazily when the function is called). + this->got_plt_->set_current_data_size(got_offset + 4); + + // Every PLT entry needs a reloc. + gsym->set_needs_dynsym_entry(); + this->rel_->add_global(gsym, elfcpp::R_ARM_JUMP_SLOT, this->got_plt_, + got_offset); + + // Note that we don't need to save the symbol. The contents of the + // PLT are independent of which symbols are used. The symbols only + // appear in the relocations. +} + +template +class Output_data_plt_arm_standard : public Output_data_plt_arm +{ + public: + Output_data_plt_arm_standard(Layout* layout, Output_data_space* got_plt) + : Output_data_plt_arm(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 +// Thumb-2 or BE8, we need to make this more flexible like GNU ld. + +// The first entry in the PLT. +template +const uint32_t Output_data_plt_arm_standard::first_plt_entry[5] = +{ + 0xe52de004, // str lr, [sp, #-4]! + 0xe59fe004, // ldr lr, [pc, #4] + 0xe08fe00e, // add lr, pc, lr + 0xe5bef008, // ldr pc, [lr, #8]! + 0x00000000, // &GOT[0] - . +}; + +template +void +Output_data_plt_arm_standard::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 +const uint32_t Output_data_plt_arm_standard::plt_entry[3] = +{ + 0xe28fc600, // add ip, pc, #0xNN00000 + 0xe28cca00, // add ip, ip, #0xNN000 + 0xe5bcf000, // ldr pc, [ip, #0xNNN]! +}; + +template +void +Output_data_plt_arm_standard::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. + +template +void +Output_data_plt_arm::do_write(Output_file* of) +{ + const off_t offset = this->offset(); + const section_size_type oview_size = + convert_to_section_size_type(this->data_size()); + unsigned char* const oview = of->get_output_view(offset, oview_size); + + const off_t got_file_offset = this->got_plt_->offset(); + const section_size_type got_size = + convert_to_section_size_type(this->got_plt_->data_size()); + unsigned char* const got_view = of->get_output_view(got_file_offset, + got_size); + unsigned char* pov = oview; + + Arm_address plt_address = this->address(); + Arm_address got_address = this->got_plt_->address(); + + // 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; + + 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 += this->get_plt_entry_size(), + got_pov += 4, + plt_offset += this->get_plt_entry_size(), + got_offset += 4) + { + // Set and adjust the PLT entry itself. + 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); + } + + gold_assert(static_cast(pov - oview) == oview_size); + gold_assert(static_cast(got_pov - got_view) == got_size); + + of->write_output_view(offset, oview_size, oview); + of->write_output_view(got_file_offset, got_size, got_view); +} + +// Create a PLT entry for a global symbol. + +template +void +Target_arm::make_plt_entry(Symbol_table* symtab, Layout* layout, + Symbol* gsym) +{ + if (gsym->has_plt_offset()) + return; + + if (this->plt_ == NULL) + { + // Create the GOT sections first. + this->got_section(symtab, layout); + + 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), + this->plt_, ORDER_PLT, false); + } + this->plt_->add_entry(gsym); +} + +// Return the number of entries in the PLT. + +template +unsigned int +Target_arm::plt_entry_count() const +{ + if (this->plt_ == NULL) + return 0; + return this->plt_->entry_count(); +} + +// Return the offset of the first non-reserved PLT entry. + +template +unsigned int +Target_arm::first_plt_entry_offset() const +{ + return this->plt_->first_plt_entry_offset(); +} + +// Return the size of each PLT entry. + +template +unsigned int +Target_arm::plt_entry_size() const +{ + return this->plt_->get_plt_entry_size(); +} + +// Get the section to use for TLS_DESC relocations. + +template +typename Target_arm::Reloc_section* +Target_arm::rel_tls_desc_section(Layout* layout) const +{ + return this->plt_section()->rel_tls_desc(layout); +} + +// Define the _TLS_MODULE_BASE_ symbol in the TLS segment. + +template +void +Target_arm::define_tls_base_symbol( + Symbol_table* symtab, + Layout* layout) +{ + if (this->tls_base_symbol_defined_) + return; + + Output_segment* tls_segment = layout->tls_segment(); + if (tls_segment != NULL) + { + bool is_exec = parameters->options().output_is_executable(); + symtab->define_in_output_segment("_TLS_MODULE_BASE_", NULL, + Symbol_table::PREDEFINED, + tls_segment, 0, 0, + elfcpp::STT_TLS, + elfcpp::STB_LOCAL, + elfcpp::STV_HIDDEN, 0, + (is_exec + ? Symbol::SEGMENT_END + : Symbol::SEGMENT_START), + true); + } + this->tls_base_symbol_defined_ = true; +} + +// Create a GOT entry for the TLS module index. + +template +unsigned int +Target_arm::got_mod_index_entry( + Symbol_table* symtab, + Layout* layout, + Sized_relobj_file<32, big_endian>* object) +{ + if (this->got_mod_index_offset_ == -1U) + { + gold_assert(symtab != NULL && layout != NULL && object != NULL); + Arm_output_data_got* got = this->got_section(symtab, layout); + unsigned int got_offset; + if (!parameters->doing_static_link()) + { + got_offset = got->add_constant(0); + Reloc_section* rel_dyn = this->rel_dyn_section(layout); + rel_dyn->add_local(object, 0, elfcpp::R_ARM_TLS_DTPMOD32, got, + got_offset); + } + else + { + // We are doing a static link. Just mark it as belong to module 1, + // the executable. + got_offset = got->add_constant(1); + } + + got->add_constant(0); + this->got_mod_index_offset_ = got_offset; + } + return this->got_mod_index_offset_; +} + +// Optimize the TLS relocation type based on what we know about the +// symbol. IS_FINAL is true if the final address of this symbol is +// known at link time. + +template +tls::Tls_optimization +Target_arm::optimize_tls_reloc(bool, int) +{ + // FIXME: Currently we do not do any TLS optimization. + return tls::TLSOPT_NONE; +} + +// Get the Reference_flags for a particular relocation. + +template +int +Target_arm::Scan::get_reference_flags(unsigned int r_type) +{ + switch (r_type) + { + case elfcpp::R_ARM_NONE: + case elfcpp::R_ARM_V4BX: + case elfcpp::R_ARM_GNU_VTENTRY: + case elfcpp::R_ARM_GNU_VTINHERIT: + // No symbol reference. + return 0; + + case elfcpp::R_ARM_ABS32: + case elfcpp::R_ARM_ABS16: + case elfcpp::R_ARM_ABS12: + case elfcpp::R_ARM_THM_ABS5: + case elfcpp::R_ARM_ABS8: + case elfcpp::R_ARM_BASE_ABS: + case elfcpp::R_ARM_MOVW_ABS_NC: + case elfcpp::R_ARM_MOVT_ABS: + case elfcpp::R_ARM_THM_MOVW_ABS_NC: + case elfcpp::R_ARM_THM_MOVT_ABS: + case elfcpp::R_ARM_ABS32_NOI: + return Symbol::ABSOLUTE_REF; + + case elfcpp::R_ARM_REL32: + case elfcpp::R_ARM_LDR_PC_G0: + case elfcpp::R_ARM_SBREL32: + case elfcpp::R_ARM_THM_PC8: + case elfcpp::R_ARM_BASE_PREL: + case elfcpp::R_ARM_MOVW_PREL_NC: + case elfcpp::R_ARM_MOVT_PREL: + case elfcpp::R_ARM_THM_MOVW_PREL_NC: + case elfcpp::R_ARM_THM_MOVT_PREL: + case elfcpp::R_ARM_THM_ALU_PREL_11_0: + case elfcpp::R_ARM_THM_PC12: + case elfcpp::R_ARM_REL32_NOI: + case elfcpp::R_ARM_ALU_PC_G0_NC: + case elfcpp::R_ARM_ALU_PC_G0: + case elfcpp::R_ARM_ALU_PC_G1_NC: + case elfcpp::R_ARM_ALU_PC_G1: + case elfcpp::R_ARM_ALU_PC_G2: + case elfcpp::R_ARM_LDR_PC_G1: + case elfcpp::R_ARM_LDR_PC_G2: + case elfcpp::R_ARM_LDRS_PC_G0: + case elfcpp::R_ARM_LDRS_PC_G1: + case elfcpp::R_ARM_LDRS_PC_G2: + case elfcpp::R_ARM_LDC_PC_G0: + case elfcpp::R_ARM_LDC_PC_G1: + case elfcpp::R_ARM_LDC_PC_G2: + case elfcpp::R_ARM_ALU_SB_G0_NC: + case elfcpp::R_ARM_ALU_SB_G0: + case elfcpp::R_ARM_ALU_SB_G1_NC: + case elfcpp::R_ARM_ALU_SB_G1: + case elfcpp::R_ARM_ALU_SB_G2: + case elfcpp::R_ARM_LDR_SB_G0: + case elfcpp::R_ARM_LDR_SB_G1: + case elfcpp::R_ARM_LDR_SB_G2: + case elfcpp::R_ARM_LDRS_SB_G0: + case elfcpp::R_ARM_LDRS_SB_G1: + case elfcpp::R_ARM_LDRS_SB_G2: + case elfcpp::R_ARM_LDC_SB_G0: + case elfcpp::R_ARM_LDC_SB_G1: + case elfcpp::R_ARM_LDC_SB_G2: + case elfcpp::R_ARM_MOVW_BREL_NC: + case elfcpp::R_ARM_MOVT_BREL: + case elfcpp::R_ARM_MOVW_BREL: + case elfcpp::R_ARM_THM_MOVW_BREL_NC: + case elfcpp::R_ARM_THM_MOVT_BREL: + case elfcpp::R_ARM_THM_MOVW_BREL: + case elfcpp::R_ARM_GOTOFF32: + case elfcpp::R_ARM_GOTOFF12: + case elfcpp::R_ARM_SBREL31: + return Symbol::RELATIVE_REF; + + case elfcpp::R_ARM_PLT32: + case elfcpp::R_ARM_CALL: + case elfcpp::R_ARM_JUMP24: + case elfcpp::R_ARM_THM_CALL: + case elfcpp::R_ARM_THM_JUMP24: + case elfcpp::R_ARM_THM_JUMP19: + case elfcpp::R_ARM_THM_JUMP6: + case elfcpp::R_ARM_THM_JUMP11: + case elfcpp::R_ARM_THM_JUMP8: + // R_ARM_PREL31 is not used to relocate call/jump instructions but + // in unwind tables. It may point to functions via PLTs. + // So we treat it like call/jump relocations above. + case elfcpp::R_ARM_PREL31: + return Symbol::FUNCTION_CALL | Symbol::RELATIVE_REF; + + case elfcpp::R_ARM_GOT_BREL: + case elfcpp::R_ARM_GOT_ABS: + case elfcpp::R_ARM_GOT_PREL: + // Absolute in GOT. + return Symbol::ABSOLUTE_REF; + + case elfcpp::R_ARM_TLS_GD32: // Global-dynamic + case elfcpp::R_ARM_TLS_LDM32: // Local-dynamic + case elfcpp::R_ARM_TLS_LDO32: // Alternate local-dynamic + case elfcpp::R_ARM_TLS_IE32: // Initial-exec + case elfcpp::R_ARM_TLS_LE32: // Local-exec + return Symbol::TLS_REF; + + case elfcpp::R_ARM_TARGET1: + case elfcpp::R_ARM_TARGET2: + case elfcpp::R_ARM_COPY: + case elfcpp::R_ARM_GLOB_DAT: + case elfcpp::R_ARM_JUMP_SLOT: + case elfcpp::R_ARM_RELATIVE: + case elfcpp::R_ARM_PC24: + case elfcpp::R_ARM_LDR_SBREL_11_0_NC: + case elfcpp::R_ARM_ALU_SBREL_19_12_NC: + case elfcpp::R_ARM_ALU_SBREL_27_20_CK: + default: + // Not expected. We will give an error later. + return 0; + } +} + +// Report an unsupported relocation against a local symbol. + +template +void +Target_arm::Scan::unsupported_reloc_local( + Sized_relobj_file<32, big_endian>* object, + unsigned int r_type) +{ + gold_error(_("%s: unsupported reloc %u against local symbol"), + object->name().c_str(), r_type); +} + +// We are about to emit a dynamic relocation of type R_TYPE. If the +// dynamic linker does not support it, issue an error. The GNU linker +// only issues a non-PIC error for an allocated read-only section. +// Here we know the section is allocated, but we don't know that it is +// read-only. But we check for all the relocation types which the +// glibc dynamic linker supports, so it seems appropriate to issue an +// error even if the section is not read-only. + +template +void +Target_arm::Scan::check_non_pic(Relobj* object, + unsigned int r_type) +{ + switch (r_type) + { + // These are the relocation types supported by glibc for ARM. + case elfcpp::R_ARM_RELATIVE: + case elfcpp::R_ARM_COPY: + case elfcpp::R_ARM_GLOB_DAT: + case elfcpp::R_ARM_JUMP_SLOT: + case elfcpp::R_ARM_ABS32: + case elfcpp::R_ARM_ABS32_NOI: + case elfcpp::R_ARM_PC24: + // FIXME: The following 3 types are not supported by Android's dynamic + // linker. + case elfcpp::R_ARM_TLS_DTPMOD32: + case elfcpp::R_ARM_TLS_DTPOFF32: + case elfcpp::R_ARM_TLS_TPOFF32: + return; + + default: + { + // This prevents us from issuing more than one error per reloc + // section. But we can still wind up issuing more than one + // error per object file. + if (this->issued_non_pic_error_) + return; + const Arm_reloc_property* reloc_property = + arm_reloc_property_table->get_reloc_property(r_type); + gold_assert(reloc_property != NULL); + object->error(_("requires unsupported dynamic reloc %s; " + "recompile with -fPIC"), + reloc_property->name().c_str()); + this->issued_non_pic_error_ = true; + return; + } + + case elfcpp::R_ARM_NONE: + gold_unreachable(); + } +} + +// Scan a relocation for a local symbol. +// FIXME: This only handles a subset of relocation types used by Android +// on ARM v5te devices. + +template +inline void +Target_arm::Scan::local(Symbol_table* symtab, + Layout* layout, + Target_arm* target, + Sized_relobj_file<32, big_endian>* object, + unsigned int data_shndx, + Output_section* output_section, + const elfcpp::Rel<32, big_endian>& reloc, + unsigned int r_type, + const elfcpp::Sym<32, big_endian>& lsym, + bool is_discarded) +{ + if (is_discarded) + return; + + r_type = get_real_reloc_type(r_type); + switch (r_type) + { + case elfcpp::R_ARM_NONE: + case elfcpp::R_ARM_V4BX: + case elfcpp::R_ARM_GNU_VTENTRY: + case elfcpp::R_ARM_GNU_VTINHERIT: + break; + + case elfcpp::R_ARM_ABS32: + case elfcpp::R_ARM_ABS32_NOI: + // If building a shared library (or a position-independent + // executable), we need to create a dynamic relocation for + // this location. The relocation applied at link time will + // apply the link-time value, so we flag the location with + // an R_ARM_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()); + // 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()); + } + break; + + case elfcpp::R_ARM_ABS16: + case elfcpp::R_ARM_ABS12: + case elfcpp::R_ARM_THM_ABS5: + case elfcpp::R_ARM_ABS8: + case elfcpp::R_ARM_BASE_ABS: + case elfcpp::R_ARM_MOVW_ABS_NC: + case elfcpp::R_ARM_MOVT_ABS: + case elfcpp::R_ARM_THM_MOVW_ABS_NC: + case elfcpp::R_ARM_THM_MOVT_ABS: + // If building a shared library (or a position-independent + // executable), we need to create a dynamic relocation for + // this location. Because the addend needs to remain in the + // 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); + unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); + 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); + 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(_("section symbol %u has bad shndx %u"), + r_sym, shndx); + else + rel_dyn->add_local_section(object, shndx, + r_type, output_section, + data_shndx, reloc.get_r_offset()); + } + } + break; + + case elfcpp::R_ARM_REL32: + case elfcpp::R_ARM_LDR_PC_G0: + case elfcpp::R_ARM_SBREL32: + case elfcpp::R_ARM_THM_CALL: + case elfcpp::R_ARM_THM_PC8: + case elfcpp::R_ARM_BASE_PREL: + case elfcpp::R_ARM_PLT32: + case elfcpp::R_ARM_CALL: + case elfcpp::R_ARM_JUMP24: + case elfcpp::R_ARM_THM_JUMP24: + case elfcpp::R_ARM_SBREL31: + case elfcpp::R_ARM_PREL31: + case elfcpp::R_ARM_MOVW_PREL_NC: + case elfcpp::R_ARM_MOVT_PREL: + case elfcpp::R_ARM_THM_MOVW_PREL_NC: + case elfcpp::R_ARM_THM_MOVT_PREL: + case elfcpp::R_ARM_THM_JUMP19: + case elfcpp::R_ARM_THM_JUMP6: + case elfcpp::R_ARM_THM_ALU_PREL_11_0: + case elfcpp::R_ARM_THM_PC12: + case elfcpp::R_ARM_REL32_NOI: + case elfcpp::R_ARM_ALU_PC_G0_NC: + case elfcpp::R_ARM_ALU_PC_G0: + case elfcpp::R_ARM_ALU_PC_G1_NC: + case elfcpp::R_ARM_ALU_PC_G1: + case elfcpp::R_ARM_ALU_PC_G2: + case elfcpp::R_ARM_LDR_PC_G1: + case elfcpp::R_ARM_LDR_PC_G2: + case elfcpp::R_ARM_LDRS_PC_G0: + case elfcpp::R_ARM_LDRS_PC_G1: + case elfcpp::R_ARM_LDRS_PC_G2: + case elfcpp::R_ARM_LDC_PC_G0: + case elfcpp::R_ARM_LDC_PC_G1: + case elfcpp::R_ARM_LDC_PC_G2: + case elfcpp::R_ARM_ALU_SB_G0_NC: + case elfcpp::R_ARM_ALU_SB_G0: + case elfcpp::R_ARM_ALU_SB_G1_NC: + case elfcpp::R_ARM_ALU_SB_G1: + case elfcpp::R_ARM_ALU_SB_G2: + case elfcpp::R_ARM_LDR_SB_G0: + case elfcpp::R_ARM_LDR_SB_G1: + case elfcpp::R_ARM_LDR_SB_G2: + case elfcpp::R_ARM_LDRS_SB_G0: + case elfcpp::R_ARM_LDRS_SB_G1: + case elfcpp::R_ARM_LDRS_SB_G2: + case elfcpp::R_ARM_LDC_SB_G0: + case elfcpp::R_ARM_LDC_SB_G1: + case elfcpp::R_ARM_LDC_SB_G2: + case elfcpp::R_ARM_MOVW_BREL_NC: + case elfcpp::R_ARM_MOVT_BREL: + case elfcpp::R_ARM_MOVW_BREL: + case elfcpp::R_ARM_THM_MOVW_BREL_NC: + case elfcpp::R_ARM_THM_MOVT_BREL: + case elfcpp::R_ARM_THM_MOVW_BREL: + case elfcpp::R_ARM_THM_JUMP11: + case elfcpp::R_ARM_THM_JUMP8: + // We don't need to do anything for a relative addressing relocation + // against a local symbol if it does not reference the GOT. + break; + + case elfcpp::R_ARM_GOTOFF32: + case elfcpp::R_ARM_GOTOFF12: + // We need a GOT section: + target->got_section(symtab, layout); + break; + + case elfcpp::R_ARM_GOT_BREL: + case elfcpp::R_ARM_GOT_PREL: + { + // The symbol requires a GOT entry. + Arm_output_data_got* got = + target->got_section(symtab, layout); + unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); + if (got->add_local(object, r_sym, GOT_TYPE_STANDARD)) + { + // 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 r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); + rel_dyn->add_local_relative( + object, r_sym, elfcpp::R_ARM_RELATIVE, got, + object->local_got_offset(r_sym, GOT_TYPE_STANDARD)); + } + } + } + break; + + case elfcpp::R_ARM_TARGET1: + case elfcpp::R_ARM_TARGET2: + // This should have been mapped to another type already. + // Fall through. + case elfcpp::R_ARM_COPY: + case elfcpp::R_ARM_GLOB_DAT: + case elfcpp::R_ARM_JUMP_SLOT: + case elfcpp::R_ARM_RELATIVE: + // These are relocations which should only be seen by the + // dynamic linker, and should never be seen here. + gold_error(_("%s: unexpected reloc %u in object file"), + object->name().c_str(), r_type); + break; + + + // These are initial TLS relocs, which are expected when + // linking. + case elfcpp::R_ARM_TLS_GD32: // Global-dynamic + case elfcpp::R_ARM_TLS_LDM32: // Local-dynamic + case elfcpp::R_ARM_TLS_LDO32: // Alternate local-dynamic + case elfcpp::R_ARM_TLS_IE32: // Initial-exec + case elfcpp::R_ARM_TLS_LE32: // Local-exec + { + bool output_is_shared = parameters->options().shared(); + const tls::Tls_optimization optimized_type + = Target_arm::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* 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); + break; + } + + if (!parameters->doing_static_link()) + got->add_local_pair_with_rel(object, r_sym, shndx, + GOT_TYPE_TLS_PAIR, + target->rel_dyn_section(layout), + elfcpp::R_ARM_TLS_DTPMOD32); + else + got->add_tls_gd32_with_static_reloc(GOT_TYPE_TLS_PAIR, + object, r_sym); + } + else + // FIXME: TLS optimization not supported yet. + gold_unreachable(); + break; + + 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); + } + else + // FIXME: TLS optimization not supported yet. + gold_unreachable(); + break; + + case elfcpp::R_ARM_TLS_LDO32: // Alternate local-dynamic + break; + + case elfcpp::R_ARM_TLS_IE32: // Initial-exec + layout->set_has_static_tls(); + if (optimized_type == tls::TLSOPT_NONE) + { + // Create a GOT entry for the tp-relative offset. + Arm_output_data_got* got + = target->got_section(symtab, layout); + unsigned int r_sym = + elfcpp::elf_r_sym<32>(reloc.get_r_info()); + if (!parameters->doing_static_link()) + got->add_local_with_rel(object, r_sym, GOT_TYPE_TLS_OFFSET, + target->rel_dyn_section(layout), + elfcpp::R_ARM_TLS_TPOFF32); + else if (!object->local_has_got_offset(r_sym, + GOT_TYPE_TLS_OFFSET)) + { + got->add_local(object, r_sym, GOT_TYPE_TLS_OFFSET); + unsigned int got_offset = + object->local_got_offset(r_sym, GOT_TYPE_TLS_OFFSET); + got->add_static_reloc(got_offset, + elfcpp::R_ARM_TLS_TPOFF32, object, + r_sym); + } + } + else + // FIXME: TLS optimization not supported yet. + gold_unreachable(); + break; + + case elfcpp::R_ARM_TLS_LE32: // Local-exec + 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()); + 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, + reloc.get_r_offset()); + } + break; + + default: + gold_unreachable(); + } + } + break; + + case elfcpp::R_ARM_PC24: + case elfcpp::R_ARM_LDR_SBREL_11_0_NC: + case elfcpp::R_ARM_ALU_SBREL_19_12_NC: + case elfcpp::R_ARM_ALU_SBREL_27_20_CK: + default: + unsupported_reloc_local(object, r_type); + break; + } +} + +// Report an unsupported relocation against a global symbol. + +template +void +Target_arm::Scan::unsupported_reloc_global( + Sized_relobj_file<32, big_endian>* object, + unsigned int r_type, + Symbol* gsym) +{ + gold_error(_("%s: unsupported reloc %u against global symbol %s"), + object->name().c_str(), r_type, gsym->demangled_name().c_str()); +} + +template +inline bool +Target_arm::Scan::possible_function_pointer_reloc( + unsigned int r_type) +{ + switch (r_type) + { + case elfcpp::R_ARM_PC24: + case elfcpp::R_ARM_THM_CALL: + case elfcpp::R_ARM_PLT32: + case elfcpp::R_ARM_CALL: + case elfcpp::R_ARM_JUMP24: + case elfcpp::R_ARM_THM_JUMP24: + case elfcpp::R_ARM_SBREL31: + case elfcpp::R_ARM_PREL31: + case elfcpp::R_ARM_THM_JUMP19: + case elfcpp::R_ARM_THM_JUMP6: + case elfcpp::R_ARM_THM_JUMP11: + case elfcpp::R_ARM_THM_JUMP8: + // All the relocations above are branches except SBREL31 and PREL31. + return false; + + default: + // Be conservative and assume this is a function pointer. + return true; + } +} + +template +inline bool +Target_arm::Scan::local_reloc_may_be_function_pointer( + Symbol_table*, + Layout*, + Target_arm* target, + Sized_relobj_file<32, big_endian>*, + unsigned int, + Output_section*, + const elfcpp::Rel<32, big_endian>&, + unsigned int r_type, + const elfcpp::Sym<32, big_endian>&) +{ + r_type = target->get_real_reloc_type(r_type); + return possible_function_pointer_reloc(r_type); +} + +template +inline bool +Target_arm::Scan::global_reloc_may_be_function_pointer( + Symbol_table*, + Layout*, + Target_arm* target, + Sized_relobj_file<32, big_endian>*, + unsigned int, + Output_section*, + const elfcpp::Rel<32, big_endian>&, + unsigned int r_type, + Symbol* gsym) +{ + // GOT is not a function. + if (strcmp(gsym->name(), "_GLOBAL_OFFSET_TABLE_") == 0) + return false; + + r_type = target->get_real_reloc_type(r_type); + return possible_function_pointer_reloc(r_type); +} + +// Scan a relocation for a global symbol. + +template +inline void +Target_arm::Scan::global(Symbol_table* symtab, + Layout* layout, + Target_arm* target, + Sized_relobj_file<32, big_endian>* object, + unsigned int data_shndx, + Output_section* output_section, + const elfcpp::Rel<32, big_endian>& reloc, + unsigned int r_type, + Symbol* gsym) +{ + // A reference to _GLOBAL_OFFSET_TABLE_ implies that we need a got + // section. We check here to avoid creating a dynamic reloc against + // _GLOBAL_OFFSET_TABLE_. + if (!target->has_got_section() + && strcmp(gsym->name(), "_GLOBAL_OFFSET_TABLE_") == 0) + target->got_section(symtab, layout); + + r_type = get_real_reloc_type(r_type); + switch (r_type) + { + case elfcpp::R_ARM_NONE: + case elfcpp::R_ARM_V4BX: + case elfcpp::R_ARM_GNU_VTENTRY: + case elfcpp::R_ARM_GNU_VTINHERIT: + break; + + case elfcpp::R_ARM_ABS32: + case elfcpp::R_ARM_ABS16: + case elfcpp::R_ARM_ABS12: + case elfcpp::R_ARM_THM_ABS5: + case elfcpp::R_ARM_ABS8: + case elfcpp::R_ARM_BASE_ABS: + case elfcpp::R_ARM_MOVW_ABS_NC: + case elfcpp::R_ARM_MOVT_ABS: + case elfcpp::R_ARM_THM_MOVW_ABS_NC: + case elfcpp::R_ARM_THM_MOVT_ABS: + 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 + || 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 + { + 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()); + } + } + } + break; + + case elfcpp::R_ARM_GOTOFF32: + case elfcpp::R_ARM_GOTOFF12: + // 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: + case elfcpp::R_ARM_THM_PC8: + case elfcpp::R_ARM_BASE_PREL: + case elfcpp::R_ARM_MOVW_PREL_NC: + case elfcpp::R_ARM_MOVT_PREL: + case elfcpp::R_ARM_THM_MOVW_PREL_NC: + case elfcpp::R_ARM_THM_MOVT_PREL: + case elfcpp::R_ARM_THM_ALU_PREL_11_0: + case elfcpp::R_ARM_THM_PC12: + case elfcpp::R_ARM_REL32_NOI: + case elfcpp::R_ARM_ALU_PC_G0_NC: + case elfcpp::R_ARM_ALU_PC_G0: + case elfcpp::R_ARM_ALU_PC_G1_NC: + case elfcpp::R_ARM_ALU_PC_G1: + case elfcpp::R_ARM_ALU_PC_G2: + case elfcpp::R_ARM_LDR_PC_G1: + case elfcpp::R_ARM_LDR_PC_G2: + case elfcpp::R_ARM_LDRS_PC_G0: + case elfcpp::R_ARM_LDRS_PC_G1: + case elfcpp::R_ARM_LDRS_PC_G2: + case elfcpp::R_ARM_LDC_PC_G0: + case elfcpp::R_ARM_LDC_PC_G1: + case elfcpp::R_ARM_LDC_PC_G2: + case elfcpp::R_ARM_ALU_SB_G0_NC: + case elfcpp::R_ARM_ALU_SB_G0: + case elfcpp::R_ARM_ALU_SB_G1_NC: + case elfcpp::R_ARM_ALU_SB_G1: + case elfcpp::R_ARM_ALU_SB_G2: + case elfcpp::R_ARM_LDR_SB_G0: + case elfcpp::R_ARM_LDR_SB_G1: + case elfcpp::R_ARM_LDR_SB_G2: + case elfcpp::R_ARM_LDRS_SB_G0: + case elfcpp::R_ARM_LDRS_SB_G1: + case elfcpp::R_ARM_LDRS_SB_G2: + case elfcpp::R_ARM_LDC_SB_G0: + case elfcpp::R_ARM_LDC_SB_G1: + case elfcpp::R_ARM_LDC_SB_G2: + case elfcpp::R_ARM_MOVW_BREL_NC: + case elfcpp::R_ARM_MOVT_BREL: + case elfcpp::R_ARM_MOVW_BREL: + case elfcpp::R_ARM_THM_MOVW_BREL_NC: + case elfcpp::R_ARM_THM_MOVT_BREL: + case elfcpp::R_ARM_THM_MOVW_BREL: + // Relative addressing relocations. + { + // Make a dynamic relocation if necessary. + if (gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type))) + { + if (target->may_need_copy_reloc(gsym)) + { + target->copy_reloc(symtab, layout, object, + data_shndx, output_section, gsym, reloc); + } + 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()); + } + } + } + break; + + case elfcpp::R_ARM_THM_CALL: + case elfcpp::R_ARM_PLT32: + case elfcpp::R_ARM_CALL: + case elfcpp::R_ARM_JUMP24: + case elfcpp::R_ARM_THM_JUMP24: + case elfcpp::R_ARM_SBREL31: + case elfcpp::R_ARM_PREL31: + case elfcpp::R_ARM_THM_JUMP19: + case elfcpp::R_ARM_THM_JUMP6: + case elfcpp::R_ARM_THM_JUMP11: + case elfcpp::R_ARM_THM_JUMP8: + // All the relocation above are branches except for the PREL31 ones. + // A PREL31 relocation can point to a personality function in a shared + // library. In that case we want to use a PLT because we want to + // call the personality routine and the dynamic linkers we care about + // do not support dynamic PREL31 relocations. An REL31 relocation may + // point to a function whose unwinding behaviour is being described but + // we will not mistakenly generate a PLT for that because we should use + // a local section symbol. + + // If the symbol is fully resolved, this is just a relative + // local reloc. Otherwise we need a PLT entry. + if (gsym->final_value_is_known()) + break; + // If building a shared library, we can also skip the PLT entry + // 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()) + break; + target->make_plt_entry(symtab, layout, gsym); + break; + + case elfcpp::R_ARM_GOT_BREL: + case elfcpp::R_ARM_GOT_ABS: + case elfcpp::R_ARM_GOT_PREL: + { + // The symbol requires a GOT entry. + Arm_output_data_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 + // GOT entry with a dynamic relocation. + Reloc_section* rel_dyn = target->rel_dyn_section(layout); + if (gsym->is_from_dynobj() + || gsym->is_undefined() + || gsym->is_preemptible() + || (gsym->visibility() == elfcpp::STV_PROTECTED + && parameters->options().shared())) + got->add_global_with_rel(gsym, GOT_TYPE_STANDARD, + rel_dyn, elfcpp::R_ARM_GLOB_DAT); + else + { + if (got->add_global(gsym, GOT_TYPE_STANDARD)) + rel_dyn->add_global_relative( + gsym, elfcpp::R_ARM_RELATIVE, got, + gsym->got_offset(GOT_TYPE_STANDARD)); + } + } + } + break; + + case elfcpp::R_ARM_TARGET1: + case elfcpp::R_ARM_TARGET2: + // These should have been mapped to other types already. + // Fall through. + case elfcpp::R_ARM_COPY: + case elfcpp::R_ARM_GLOB_DAT: + case elfcpp::R_ARM_JUMP_SLOT: + case elfcpp::R_ARM_RELATIVE: + // These are relocations which should only be seen by the + // dynamic linker, and should never be seen here. + gold_error(_("%s: unexpected reloc %u in object file"), + object->name().c_str(), r_type); + break; + + // These are initial tls relocs, which are expected when + // linking. + case elfcpp::R_ARM_TLS_GD32: // Global-dynamic + case elfcpp::R_ARM_TLS_LDM32: // Local-dynamic + case elfcpp::R_ARM_TLS_LDO32: // Alternate local-dynamic + case elfcpp::R_ARM_TLS_IE32: // Initial-exec + case elfcpp::R_ARM_TLS_LE32: // Local-exec + { + const bool is_final = gsym->final_value_is_known(); + const tls::Tls_optimization optimized_type + = Target_arm::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* 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), + elfcpp::R_ARM_TLS_DTPMOD32, + elfcpp::R_ARM_TLS_DTPOFF32); + else + got->add_tls_gd32_with_static_reloc(GOT_TYPE_TLS_PAIR, gsym); + } + else + // FIXME: TLS optimization not supported yet. + gold_unreachable(); + break; + + 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); + } + else + // FIXME: TLS optimization not supported yet. + gold_unreachable(); + break; + + case elfcpp::R_ARM_TLS_LDO32: // Alternate local-dynamic + break; + + case elfcpp::R_ARM_TLS_IE32: // Initial-exec + layout->set_has_static_tls(); + if (optimized_type == tls::TLSOPT_NONE) + { + // Create a GOT entry for the tp-relative offset. + Arm_output_data_got* got + = target->got_section(symtab, layout); + if (!parameters->doing_static_link()) + got->add_global_with_rel(gsym, GOT_TYPE_TLS_OFFSET, + target->rel_dyn_section(layout), + elfcpp::R_ARM_TLS_TPOFF32); + else if (!gsym->has_got_offset(GOT_TYPE_TLS_OFFSET)) + { + got->add_global(gsym, GOT_TYPE_TLS_OFFSET); + unsigned int got_offset = + gsym->got_offset(GOT_TYPE_TLS_OFFSET); + got->add_static_reloc(got_offset, + elfcpp::R_ARM_TLS_TPOFF32, gsym); + } + } + else + // FIXME: TLS optimization not supported yet. + gold_unreachable(); + break; + + case elfcpp::R_ARM_TLS_LE32: // Local-exec + 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, + output_section, object, + data_shndx, reloc.get_r_offset()); + } + break; + + default: + gold_unreachable(); + } + } + break; + + case elfcpp::R_ARM_PC24: + case elfcpp::R_ARM_LDR_SBREL_11_0_NC: + case elfcpp::R_ARM_ALU_SBREL_19_12_NC: + case elfcpp::R_ARM_ALU_SBREL_27_20_CK: + default: + unsupported_reloc_global(object, r_type, gsym); + break; + } +} + +// Process relocations for gc. + +template +void +Target_arm::gc_process_relocs( + Symbol_table* symtab, + Layout* layout, + Sized_relobj_file<32, big_endian>* 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) +{ + typedef Target_arm Arm; + typedef typename Target_arm::Scan Scan; + + gold::gc_process_relocs<32, big_endian, Arm, elfcpp::SHT_REL, Scan, + typename Target_arm::Relocatable_size_for_reloc>( + symtab, + layout, + this, + object, + data_shndx, + prelocs, + reloc_count, + output_section, + needs_special_offset_handling, + local_symbol_count, + plocal_symbols); +} + +// Scan relocations for a section. + +template +void +Target_arm::scan_relocs(Symbol_table* symtab, + Layout* layout, + Sized_relobj_file<32, 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) +{ + typedef typename Target_arm::Scan Scan; + if (sh_type == elfcpp::SHT_RELA) + { + gold_error(_("%s: unsupported RELA reloc section"), + object->name().c_str()); + return; + } + + gold::scan_relocs<32, big_endian, Target_arm, elfcpp::SHT_REL, Scan>( + symtab, + layout, + this, + object, + data_shndx, + prelocs, + reloc_count, + output_section, + needs_special_offset_handling, + local_symbol_count, + plocal_symbols); +} + +// Finalize the sections. + +template +void +Target_arm::do_finalize_sections( + Layout* layout, + const Input_objects* input_objects, + Symbol_table*) +{ + bool merged_any_attributes = false; + // Merge processor-specific flags. + for (Input_objects::Relobj_iterator p = input_objects->relobj_begin(); + p != input_objects->relobj_end(); + ++p) + { + Arm_relobj* arm_relobj = + Arm_relobj::as_arm_relobj(*p); + if (arm_relobj->merge_flags_and_attributes()) + { + this->merge_processor_specific_flags( + arm_relobj->name(), + arm_relobj->processor_specific_flags()); + this->merge_object_attributes(arm_relobj->name().c_str(), + arm_relobj->attributes_section_data()); + merged_any_attributes = true; + } + } + + for (Input_objects::Dynobj_iterator p = input_objects->dynobj_begin(); + p != input_objects->dynobj_end(); + ++p) + { + Arm_dynobj* arm_dynobj = + Arm_dynobj::as_arm_dynobj(*p); + this->merge_processor_specific_flags( + arm_dynobj->name(), + arm_dynobj->processor_specific_flags()); + this->merge_object_attributes(arm_dynobj->name().c_str(), + arm_dynobj->attributes_section_data()); + merged_any_attributes = true; + } + + // Create an empty uninitialized attribute section if we still don't have it + // at this moment. This happens if there is no attributes sections in all + // inputs. + if (this->attributes_section_data_ == NULL) + this->attributes_section_data_ = new Attributes_section_data(NULL, 0); + + const Object_attribute* cpu_arch_attr = + this->get_aeabi_object_attribute(elfcpp::Tag_CPU_arch); + // Check if we need to use Cortex-A8 workaround. + if (parameters->options().user_set_fix_cortex_a8()) + this->fix_cortex_a8_ = parameters->options().fix_cortex_a8(); + else + { + // 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. + 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)); + } + + // 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")); + + // Fill in some more dynamic tags. + const Reloc_section* rel_plt = (this->plt_ == NULL + ? NULL + : this->plt_->rel_plt()); + layout->add_target_dynamic_tags(true, this->got_plt_, rel_plt, + this->rel_dyn_, true, false); + + // Emit any relocs we saved in an attempt to avoid generating COPY + // relocs. + if (this->copy_relocs_.any_saved_relocs()) + this->copy_relocs_.emit(this->rel_dyn_section(layout)); + + // Handle the .ARM.exidx section. + Output_section* exidx_section = layout->find_output_section(".ARM.exidx"); + + 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); + } + } + } + + // Create an .ARM.attributes section if we have merged any attributes + // from inputs. + if (merged_any_attributes) + { + Output_attributes_section_data* attributes_section = + new Output_attributes_section_data(*this->attributes_section_data_); + layout->add_output_section_data(".ARM.attributes", + elfcpp::SHT_ARM_ATTRIBUTES, 0, + attributes_section, ORDER_INVALID, + false); + } + + // Fix up links in section EXIDX headers. + for (Layout::Section_list::const_iterator p = layout->section_list().begin(); + p != layout->section_list().end(); + ++p) + if ((*p)->type() == elfcpp::SHT_ARM_EXIDX) + { + Arm_output_section* os = + Arm_output_section::as_arm_output_section(*p); + os->set_exidx_section_link(); + } +} + +// Return whether a direct absolute static relocation needs to be applied. +// In cases where Scan::local() or Scan::global() has created +// a dynamic relocation other than R_ARM_RELATIVE, the addend +// of the relocation is carried in the data, and we must not +// apply the static relocation. + +template +inline bool +Target_arm::Relocate::should_apply_static_reloc( + const Sized_symbol<32>* gsym, + unsigned int r_type, + bool is_32bit, + Output_section* output_section) +{ + // If the output section is not allocated, then we didn't call + // scan_relocs, we didn't create a dynamic reloc, and we must apply + // the reloc here. + if ((output_section->flags() & elfcpp::SHF_ALLOC) == 0) + return true; + + int ref_flags = Scan::get_reference_flags(r_type); + + // For local symbols, we will have created a non-RELATIVE dynamic + // relocation only if (a) the output is position independent, + // (b) the relocation is absolute (not pc- or segment-relative), and + // (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); + + // 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 + // created a RELATIVE dynamic relocation, we should apply the static + // 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); + return !has_dyn || is_rel; +} + +// Perform a relocation. + +template +inline bool +Target_arm::Relocate::relocate( + const Relocate_info<32, big_endian>* relinfo, + Target_arm* target, + Output_section* output_section, + size_t relnum, + const elfcpp::Rel<32, big_endian>& rel, + unsigned int r_type, + const Sized_symbol<32>* gsym, + const Symbol_value<32>* psymval, + unsigned char* view, + Arm_address address, + section_size_type view_size) +{ + if (view == NULL) + return true; + + typedef Arm_relocate_functions Arm_relocate_functions; + + r_type = get_real_reloc_type(r_type); + const Arm_reloc_property* reloc_property = + arm_reloc_property_table->get_implemented_static_reloc_property(r_type); + if (reloc_property == NULL) + { + std::string reloc_name = + arm_reloc_property_table->reloc_name_in_error_message(r_type); + gold_error_at_location(relinfo, relnum, rel.get_r_offset(), + _("cannot relocate %s in object file"), + reloc_name.c_str()); + return true; + } + + const Arm_relobj* object = + Arm_relobj::as_arm_relobj(relinfo->object); + + // If the final branch target of a relocation is THUMB instruction, this + // is 1. Otherwise it is 0. + Arm_address thumb_bit = 0; + Symbol_value<32> symval; + bool is_weakly_undefined_without_plt = false; + bool have_got_offset = false; + unsigned int got_offset = 0; + + // If the relocation uses the GOT entry of a symbol instead of the symbol + // itself, we don't care about whether the symbol is defined or what kind + // of symbol it is. + if (reloc_property->uses_got_entry()) + { + // Get the GOT offset. + // The GOT pointer points to the end of the GOT section. + // We need to subtract the size of the GOT section to get + // the actual offset to use in the relocation. + // TODO: We should move GOT offset computing code in TLS relocations + // to here. + switch (r_type) + { + case elfcpp::R_ARM_GOT_BREL: + case elfcpp::R_ARM_GOT_PREL: + if (gsym != NULL) + { + 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()); + } + have_got_offset = true; + break; + + default: + break; + } + } + else if (relnum != Target_arm::fake_relnum_for_stubs) + { + if (gsym != NULL) + { + // This is a global symbol. Determine if we use PLT and if the + // final target is THUMB. + if (gsym->use_plt_offset(Scan::get_reference_flags(r_type))) + { + // This uses a PLT, change the symbol value. + symval.set_output_value(target->plt_section()->address() + + gsym->plt_offset()); + psymval = &symval; + } + else if (gsym->is_weak_undefined()) + { + // This is a weakly undefined symbol and we do not use PLT + // for this relocation. A branch targeting this symbol will + // be converted into an NOP. + is_weakly_undefined_without_plt = true; + } + else if (gsym->is_undefined() && reloc_property->uses_symbol()) + { + // This relocation uses the symbol value but the symbol is + // undefined. Exit early and have the caller reporting an + // error. + return true; + } + else + { + // Set thumb bit if symbol: + // -Has type STT_ARM_TFUNC or + // -Has type STT_FUNC, is defined and with LSB in value set. + thumb_bit = + (((gsym->type() == elfcpp::STT_ARM_TFUNC) + || (gsym->type() == elfcpp::STT_FUNC + && !gsym->is_undefined() + && ((psymval->value(object, 0) & 1) != 0))) + ? 1 + : 0); + } + } + else + { + // 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; + } + } + else + { + // This is a fake relocation synthesized for a stub. It does not have + // a real symbol. We just look at the LSB of the symbol value to + // determine if the target is THUMB or not. + thumb_bit = ((psymval->value(object, 0) & 1) != 0); + } + + // Strip LSB if this points to a THUMB target. + if (thumb_bit != 0 + && reloc_property->uses_thumb_bit() + && ((psymval->value(object, 0) & 1) != 0)) + { + Arm_address stripped_value = + psymval->value(object, 0) & ~static_cast(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. + unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info()); + + // Get the addressing origin of the output segment defining the + // symbol gsym if needed (AAELF 4.6.1.2 Relocation types). + Arm_address sym_origin = 0; + if (reloc_property->uses_symbol_base()) + { + if (r_type == elfcpp::R_ARM_BASE_ABS && gsym == NULL) + // R_ARM_BASE_ABS with the NULL symbol will give the + // absolute address of the GOT origin (GOT_ORG) (see ARM IHI + // 0044C (AAELF): 4.6.1.8 Proxy generating relocations). + sym_origin = target->got_plt_section()->address(); + else if (gsym == NULL) + sym_origin = 0; + else if (gsym->source() == Symbol::IN_OUTPUT_SEGMENT) + sym_origin = gsym->output_segment()->vaddr(); + else if (gsym->source() == Symbol::IN_OUTPUT_DATA) + sym_origin = gsym->output_data()->address(); + + // TODO: Assumes the segment base to be zero for the global symbols + // till the proper support for the segment-base-relative addressing + // will be implemented. This is consistent with GNU ld. + } + + // For relative addressing relocation, find out the relative address base. + Arm_address relative_address_base = 0; + switch(reloc_property->relative_address_base()) + { + case Arm_reloc_property::RAB_NONE: + // Relocations with relative address bases RAB_TLS and RAB_tp are + // handled by relocate_tls. So we do not need to do anything here. + case Arm_reloc_property::RAB_TLS: + case Arm_reloc_property::RAB_tp: + break; + case Arm_reloc_property::RAB_B_S: + relative_address_base = sym_origin; + break; + case Arm_reloc_property::RAB_GOT_ORG: + relative_address_base = target->got_plt_section()->address(); + break; + case Arm_reloc_property::RAB_P: + relative_address_base = address; + break; + case Arm_reloc_property::RAB_Pa: + relative_address_base = address & 0xfffffffcU; + break; + default: + gold_unreachable(); + } + + typename Arm_relocate_functions::Status reloc_status = + Arm_relocate_functions::STATUS_OKAY; + bool check_overflow = reloc_property->checks_overflow(); + switch (r_type) + { + case elfcpp::R_ARM_NONE: + break; + + case elfcpp::R_ARM_ABS8: + if (should_apply_static_reloc(gsym, r_type, false, output_section)) + reloc_status = Arm_relocate_functions::abs8(view, object, psymval); + break; + + case elfcpp::R_ARM_ABS12: + if (should_apply_static_reloc(gsym, r_type, false, output_section)) + reloc_status = Arm_relocate_functions::abs12(view, object, psymval); + break; + + case elfcpp::R_ARM_ABS16: + if (should_apply_static_reloc(gsym, r_type, false, output_section)) + reloc_status = Arm_relocate_functions::abs16(view, object, psymval); + break; + + case elfcpp::R_ARM_ABS32: + if (should_apply_static_reloc(gsym, r_type, true, output_section)) + reloc_status = Arm_relocate_functions::abs32(view, object, psymval, + thumb_bit); + break; + + case elfcpp::R_ARM_ABS32_NOI: + if (should_apply_static_reloc(gsym, r_type, true, output_section)) + // No thumb bit for this relocation: (S + A) + reloc_status = Arm_relocate_functions::abs32(view, object, psymval, + 0); + break; + + case elfcpp::R_ARM_MOVW_ABS_NC: + if (should_apply_static_reloc(gsym, r_type, false, output_section)) + reloc_status = Arm_relocate_functions::movw(view, object, psymval, + 0, thumb_bit, + check_overflow); + break; + + case elfcpp::R_ARM_MOVT_ABS: + if (should_apply_static_reloc(gsym, r_type, false, output_section)) + reloc_status = Arm_relocate_functions::movt(view, object, psymval, 0); + break; + + 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); + break; + + case elfcpp::R_ARM_THM_MOVT_ABS: + if (should_apply_static_reloc(gsym, r_type, false, output_section)) + reloc_status = Arm_relocate_functions::thm_movt(view, object, + psymval, 0); + break; + + case elfcpp::R_ARM_MOVW_PREL_NC: + case elfcpp::R_ARM_MOVW_BREL_NC: + case elfcpp::R_ARM_MOVW_BREL: + reloc_status = + Arm_relocate_functions::movw(view, object, psymval, + relative_address_base, thumb_bit, + check_overflow); + break; + + case elfcpp::R_ARM_MOVT_PREL: + case elfcpp::R_ARM_MOVT_BREL: + reloc_status = + Arm_relocate_functions::movt(view, object, psymval, + relative_address_base); + break; + + case elfcpp::R_ARM_THM_MOVW_PREL_NC: + case elfcpp::R_ARM_THM_MOVW_BREL_NC: + case elfcpp::R_ARM_THM_MOVW_BREL: + reloc_status = + Arm_relocate_functions::thm_movw(view, object, psymval, + relative_address_base, + thumb_bit, check_overflow); + break; + + case elfcpp::R_ARM_THM_MOVT_PREL: + case elfcpp::R_ARM_THM_MOVT_BREL: + reloc_status = + 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); + break; + + case elfcpp::R_ARM_THM_ABS5: + if (should_apply_static_reloc(gsym, r_type, false, output_section)) + reloc_status = Arm_relocate_functions::thm_abs5(view, object, psymval); + break; + + // Thumb long branches. + case elfcpp::R_ARM_THM_CALL: + case elfcpp::R_ARM_THM_XPC22: + case elfcpp::R_ARM_THM_JUMP24: + reloc_status = + Arm_relocate_functions::thumb_branch_common( + r_type, relinfo, view, gsym, object, r_sym, psymval, address, + thumb_bit, is_weakly_undefined_without_plt); + break; + + case elfcpp::R_ARM_GOTOFF32: + { + Arm_address got_origin; + got_origin = target->got_plt_section()->address(); + reloc_status = Arm_relocate_functions::rel32(view, object, psymval, + got_origin, thumb_bit); + } + break; + + case elfcpp::R_ARM_BASE_PREL: + gold_assert(gsym != NULL); + reloc_status = + Arm_relocate_functions::base_prel(view, sym_origin, address); + break; + + case elfcpp::R_ARM_BASE_ABS: + if (should_apply_static_reloc(gsym, r_type, false, output_section)) + reloc_status = Arm_relocate_functions::base_abs(view, sym_origin); + break; + + case elfcpp::R_ARM_GOT_BREL: + gold_assert(have_got_offset); + reloc_status = Arm_relocate_functions::got_brel(view, got_offset); + break; + + case elfcpp::R_ARM_GOT_PREL: + gold_assert(have_got_offset); + // Get the address origin for GOT PLT, which is allocated right + // after the GOT section, to calculate an absolute address of + // the symbol GOT entry (got_origin + got_offset). + Arm_address got_origin; + got_origin = target->got_plt_section()->address(); + reloc_status = Arm_relocate_functions::got_prel(view, + got_origin + got_offset, + address); + break; + + case elfcpp::R_ARM_PLT32: + case elfcpp::R_ARM_CALL: + case elfcpp::R_ARM_JUMP24: + case elfcpp::R_ARM_XPC25: + gold_assert(gsym == NULL + || gsym->has_plt_offset() + || gsym->final_value_is_known() + || (gsym->is_defined() + && !gsym->is_from_dynobj() + && !gsym->is_preemptible())); + reloc_status = + Arm_relocate_functions::arm_branch_common( + r_type, relinfo, view, gsym, object, r_sym, psymval, address, + thumb_bit, is_weakly_undefined_without_plt); + break; + + case elfcpp::R_ARM_THM_JUMP19: + reloc_status = + Arm_relocate_functions::thm_jump19(view, object, psymval, address, + thumb_bit); + break; + + case elfcpp::R_ARM_THM_JUMP6: + reloc_status = + Arm_relocate_functions::thm_jump6(view, object, psymval, address); + break; + + case elfcpp::R_ARM_THM_JUMP8: + reloc_status = + Arm_relocate_functions::thm_jump8(view, object, psymval, address); + break; + + case elfcpp::R_ARM_THM_JUMP11: + reloc_status = + Arm_relocate_functions::thm_jump11(view, object, psymval, address); + break; + + case elfcpp::R_ARM_PREL31: + reloc_status = Arm_relocate_functions::prel31(view, object, psymval, + address, thumb_bit); + break; + + case elfcpp::R_ARM_V4BX: + if (target->fix_v4bx() > General_options::FIX_V4BX_NONE) + { + const bool is_v4bx_interworking = + (target->fix_v4bx() == General_options::FIX_V4BX_INTERWORKING); + reloc_status = + Arm_relocate_functions::v4bx(relinfo, view, object, address, + is_v4bx_interworking); + } + break; + + case elfcpp::R_ARM_THM_PC8: + reloc_status = + Arm_relocate_functions::thm_pc8(view, object, psymval, address); + break; + + case elfcpp::R_ARM_THM_PC12: + reloc_status = + Arm_relocate_functions::thm_pc12(view, object, psymval, address); + break; + + case elfcpp::R_ARM_THM_ALU_PREL_11_0: + reloc_status = + Arm_relocate_functions::thm_alu11(view, object, psymval, address, + thumb_bit); + break; + + case elfcpp::R_ARM_ALU_PC_G0_NC: + case elfcpp::R_ARM_ALU_PC_G0: + case elfcpp::R_ARM_ALU_PC_G1_NC: + case elfcpp::R_ARM_ALU_PC_G1: + case elfcpp::R_ARM_ALU_PC_G2: + case elfcpp::R_ARM_ALU_SB_G0_NC: + case elfcpp::R_ARM_ALU_SB_G0: + case elfcpp::R_ARM_ALU_SB_G1_NC: + case elfcpp::R_ARM_ALU_SB_G1: + case elfcpp::R_ARM_ALU_SB_G2: + reloc_status = + Arm_relocate_functions::arm_grp_alu(view, object, psymval, + reloc_property->group_index(), + relative_address_base, + thumb_bit, check_overflow); + break; + + case elfcpp::R_ARM_LDR_PC_G0: + case elfcpp::R_ARM_LDR_PC_G1: + case elfcpp::R_ARM_LDR_PC_G2: + case elfcpp::R_ARM_LDR_SB_G0: + case elfcpp::R_ARM_LDR_SB_G1: + case elfcpp::R_ARM_LDR_SB_G2: + reloc_status = + Arm_relocate_functions::arm_grp_ldr(view, object, psymval, + reloc_property->group_index(), + relative_address_base); + break; + + case elfcpp::R_ARM_LDRS_PC_G0: + case elfcpp::R_ARM_LDRS_PC_G1: + case elfcpp::R_ARM_LDRS_PC_G2: + case elfcpp::R_ARM_LDRS_SB_G0: + case elfcpp::R_ARM_LDRS_SB_G1: + case elfcpp::R_ARM_LDRS_SB_G2: + reloc_status = + Arm_relocate_functions::arm_grp_ldrs(view, object, psymval, + reloc_property->group_index(), + relative_address_base); + break; + + case elfcpp::R_ARM_LDC_PC_G0: + case elfcpp::R_ARM_LDC_PC_G1: + case elfcpp::R_ARM_LDC_PC_G2: + case elfcpp::R_ARM_LDC_SB_G0: + case elfcpp::R_ARM_LDC_SB_G1: + case elfcpp::R_ARM_LDC_SB_G2: + reloc_status = + Arm_relocate_functions::arm_grp_ldc(view, object, psymval, + reloc_property->group_index(), + relative_address_base); + break; + + // These are initial tls relocs, which are expected when + // linking. + case elfcpp::R_ARM_TLS_GD32: // Global-dynamic + case elfcpp::R_ARM_TLS_LDM32: // Local-dynamic + case elfcpp::R_ARM_TLS_LDO32: // Alternate local-dynamic + case elfcpp::R_ARM_TLS_IE32: // Initial-exec + case elfcpp::R_ARM_TLS_LE32: // Local-exec + reloc_status = + this->relocate_tls(relinfo, target, relnum, rel, r_type, gsym, psymval, + view, address, view_size); + break; + + // The known and unknown unsupported and/or deprecated relocations. + case elfcpp::R_ARM_PC24: + case elfcpp::R_ARM_LDR_SBREL_11_0_NC: + case elfcpp::R_ARM_ALU_SBREL_19_12_NC: + case elfcpp::R_ARM_ALU_SBREL_27_20_CK: + default: + // Just silently leave the method. We should get an appropriate error + // message in the scan methods. + break; + } + + // Report any errors. + switch (reloc_status) + { + case Arm_relocate_functions::STATUS_OKAY: + break; + case Arm_relocate_functions::STATUS_OVERFLOW: + gold_error_at_location(relinfo, relnum, rel.get_r_offset(), + _("relocation overflow in %s"), + reloc_property->name().c_str()); + break; + case Arm_relocate_functions::STATUS_BAD_RELOC: + gold_error_at_location( + relinfo, + relnum, + rel.get_r_offset(), + _("unexpected opcode while processing relocation %s"), + reloc_property->name().c_str()); + break; + default: + gold_unreachable(); + } + + return true; +} + +// Perform a TLS relocation. + +template +inline typename Arm_relocate_functions::Status +Target_arm::Relocate::relocate_tls( + const Relocate_info<32, big_endian>* relinfo, + Target_arm* target, + size_t relnum, + const elfcpp::Rel<32, big_endian>& 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*/ ) +{ + typedef Arm_relocate_functions ArmRelocFuncs; + typedef Relocate_functions<32, big_endian> RelocFuncs; + Output_segment* tls_segment = relinfo->layout->tls_segment(); + + const Sized_relobj_file<32, big_endian>* object = relinfo->object; + + elfcpp::Elf_types<32>::Elf_Addr value = psymval->value(object, 0); + + const bool is_final = (gsym == NULL + ? !parameters->options().shared() + : gsym->final_value_is_known()); + const tls::Tls_optimization optimized_type + = Target_arm::optimize_tls_reloc(is_final, r_type); + 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) + - target->got_size()); + } + 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. + RelocFuncs::pcrel32_unaligned(view, got_entry, address); + 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) + - 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); + return ArmRelocFuncs::STATUS_OKAY; + } + break; + + case elfcpp::R_ARM_TLS_LDO32: // Alternate local-dynamic + RelocFuncs::rel32_unaligned(view, value); + return ArmRelocFuncs::STATUS_OKAY; + + 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. + 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(); + + Arm_address got_entry = + target->got_plt_section()->address() + got_offset; + + // 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); + + // $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); + + } + return ArmRelocFuncs::STATUS_OKAY; + + default: + gold_unreachable(); + } + + gold_error_at_location(relinfo, relnum, rel.get_r_offset(), + _("unsupported reloc %u"), + r_type); + return ArmRelocFuncs::STATUS_BAD_RELOC; +} + +// Relocate section data. + +template +void +Target_arm::relocate_section( + const Relocate_info<32, big_endian>* relinfo, + unsigned int sh_type, + const unsigned char* prelocs, + size_t reloc_count, + Output_section* output_section, + bool needs_special_offset_handling, + unsigned char* view, + Arm_address address, + section_size_type view_size, + const Reloc_symbol_changes* reloc_symbol_changes) +{ + typedef typename Target_arm::Relocate Arm_relocate; + gold_assert(sh_type == elfcpp::SHT_REL); + + // See if we are relocating a relaxed input section. If so, the view + // covers the whole output section and we need to adjust accordingly. + if (needs_special_offset_handling) + { + const Output_relaxed_input_section* poris = + output_section->find_relaxed_input_section(relinfo->object, + relinfo->data_shndx); + if (poris != NULL) + { + Arm_address section_address = poris->address(); + section_size_type section_size = poris->data_size(); + + gold_assert((section_address >= address) + && ((section_address + section_size) + <= (address + view_size))); + + off_t offset = section_address - address; + view += offset; + address += offset; + view_size = section_size; + } + } + + gold::relocate_section<32, big_endian, Target_arm, elfcpp::SHT_REL, + Arm_relocate, gold::Default_comdat_behavior>( + relinfo, + this, + prelocs, + reloc_count, + output_section, + needs_special_offset_handling, + view, + address, + view_size, + reloc_symbol_changes); +} + +// Return the size of a relocation while scanning during a relocatable +// link. + +template +unsigned int +Target_arm::Relocatable_size_for_reloc::get_size_for_reloc( + unsigned int r_type, + Relobj* object) +{ + r_type = get_real_reloc_type(r_type); + const Arm_reloc_property* arp = + arm_reloc_property_table->get_implemented_static_reloc_property(r_type); + if (arp != NULL) + return arp->size(); + else + { + std::string reloc_name = + arm_reloc_property_table->reloc_name_in_error_message(r_type); + gold_error(_("%s: unexpected %s in object file"), + object->name().c_str(), reloc_name.c_str()); + return 0; + } +} + +// Scan the relocs during a relocatable link. + +template +void +Target_arm::scan_relocatable_relocs( + Symbol_table* symtab, + Layout* layout, + Sized_relobj_file<32, 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, + Relocatable_relocs* rr) +{ + gold_assert(sh_type == elfcpp::SHT_REL); + + typedef Arm_scan_relocatable_relocs Scan_relocatable_relocs; + + gold::scan_relocatable_relocs<32, big_endian, elfcpp::SHT_REL, + Scan_relocatable_relocs>( + symtab, + layout, + object, + data_shndx, + prelocs, + reloc_count, + output_section, + needs_special_offset_handling, + local_symbol_count, + plocal_symbols, + rr); +} + +// Emit relocations for a section. + +template +void +Target_arm::relocate_relocs( + const Relocate_info<32, big_endian>* relinfo, + unsigned int sh_type, + const unsigned char* prelocs, + size_t reloc_count, + Output_section* output_section, + typename elfcpp::Elf_types<32>::Elf_Off offset_in_output_section, + const Relocatable_relocs* rr, + unsigned char* view, + Arm_address view_address, + section_size_type view_size, + unsigned char* reloc_view, + section_size_type reloc_view_size) +{ + gold_assert(sh_type == elfcpp::SHT_REL); + + gold::relocate_relocs<32, big_endian, elfcpp::SHT_REL>( + relinfo, + prelocs, + reloc_count, + output_section, + offset_in_output_section, + rr, + view, + view_address, + view_size, + reloc_view, + reloc_view_size); +} + +// Perform target-specific processing in a relocatable link. This is +// only used if we use the relocation strategy RELOC_SPECIAL. + +template +void +Target_arm::relocate_special_relocatable( + const Relocate_info<32, big_endian>* relinfo, + unsigned int sh_type, + const unsigned char* preloc_in, + size_t relnum, + Output_section* output_section, + typename elfcpp::Elf_types<32>::Elf_Off offset_in_output_section, + unsigned char* view, + elfcpp::Elf_types<32>::Elf_Addr view_address, + section_size_type, + unsigned char* preloc_out) +{ + // We can only handle REL type relocation sections. + gold_assert(sh_type == elfcpp::SHT_REL); + + typedef typename Reloc_types::Reloc Reltype; + typedef typename Reloc_types::Reloc_write + Reltype_write; + const Arm_address invalid_address = static_cast(0) - 1; + + const Arm_relobj* object = + Arm_relobj::as_arm_relobj(relinfo->object); + const unsigned int local_count = object->local_symbol_count(); + + Reltype reloc(preloc_in); + Reltype_write reloc_write(preloc_out); + + elfcpp::Elf_types<32>::Elf_WXword r_info = reloc.get_r_info(); + const unsigned int r_sym = elfcpp::elf_r_sym<32>(r_info); + const unsigned int r_type = elfcpp::elf_r_type<32>(r_info); + + const Arm_reloc_property* arp = + arm_reloc_property_table->get_implemented_static_reloc_property(r_type); + gold_assert(arp != NULL); + + // Get the new symbol index. + // We only use RELOC_SPECIAL strategy in local relocations. + gold_assert(r_sym < local_count); + + // We are adjusting a section symbol. We need to find + // the symbol table index of the section symbol for + // the output section corresponding to input section + // in which this symbol is defined. + bool is_ordinary; + unsigned int shndx = object->local_symbol_input_shndx(r_sym, &is_ordinary); + gold_assert(is_ordinary); + Output_section* os = object->output_section(shndx); + gold_assert(os != NULL); + gold_assert(os->needs_symtab_index()); + unsigned int new_symndx = os->symtab_index(); + + // Get the new offset--the location in the output section where + // this relocation should be applied. + + Arm_address offset = reloc.get_r_offset(); + Arm_address new_offset; + if (offset_in_output_section != invalid_address) + new_offset = offset + offset_in_output_section; + else + { + section_offset_type sot_offset = + convert_types(offset); + section_offset_type new_sot_offset = + output_section->output_offset(object, relinfo->data_shndx, + sot_offset); + gold_assert(new_sot_offset != -1); + new_offset = new_sot_offset; + } + + // In an object file, r_offset is an offset within the section. + // In an executable or dynamic object, generated by + // --emit-relocs, r_offset is an absolute address. + if (!parameters->options().relocatable()) + { + new_offset += view_address; + if (offset_in_output_section != invalid_address) + new_offset -= offset_in_output_section; + } + + reloc_write.put_r_offset(new_offset); + reloc_write.put_r_info(elfcpp::elf_r_info<32>(new_symndx, r_type)); + + // Handle the reloc addend. + // The relocation uses a section symbol in the input file. + // We are adjusting it to use a section symbol in the output + // file. The input section symbol refers to some address in + // the input section. We need the relocation in the output + // file to refer to that same address. This adjustment to + // the addend is the same calculation we use for a simple + // absolute relocation for the input section symbol. + + const Symbol_value<32>* psymval = object->local_symbol(r_sym); + + // Handle THUMB bit. + Symbol_value<32> symval; + Arm_address thumb_bit = + object->local_symbol_is_thumb_function(r_sym) ? 1 : 0; + if (thumb_bit != 0 + && arp->uses_thumb_bit() + && ((psymval->value(object, 0) & 1) != 0)) + { + Arm_address stripped_value = + psymval->value(object, 0) & ~static_cast(1); + symval.set_output_value(stripped_value); + psymval = &symval; + } + + unsigned char* paddend = view + offset; + typename Arm_relocate_functions::Status reloc_status = + Arm_relocate_functions::STATUS_OKAY; + switch (r_type) + { + case elfcpp::R_ARM_ABS8: + reloc_status = Arm_relocate_functions::abs8(paddend, object, + psymval); + break; + + case elfcpp::R_ARM_ABS12: + reloc_status = Arm_relocate_functions::abs12(paddend, object, + psymval); + break; + + case elfcpp::R_ARM_ABS16: + reloc_status = Arm_relocate_functions::abs16(paddend, object, + psymval); + break; + + case elfcpp::R_ARM_THM_ABS5: + reloc_status = Arm_relocate_functions::thm_abs5(paddend, + object, + psymval); + break; + + case elfcpp::R_ARM_MOVW_ABS_NC: + case elfcpp::R_ARM_MOVW_PREL_NC: + case elfcpp::R_ARM_MOVW_BREL_NC: + case elfcpp::R_ARM_MOVW_BREL: + reloc_status = Arm_relocate_functions::movw( + paddend, object, psymval, 0, thumb_bit, arp->checks_overflow()); + break; + + case elfcpp::R_ARM_THM_MOVW_ABS_NC: + case elfcpp::R_ARM_THM_MOVW_PREL_NC: + case elfcpp::R_ARM_THM_MOVW_BREL_NC: + case elfcpp::R_ARM_THM_MOVW_BREL: + reloc_status = Arm_relocate_functions::thm_movw( + paddend, object, psymval, 0, thumb_bit, arp->checks_overflow()); + break; + + case elfcpp::R_ARM_THM_CALL: + case elfcpp::R_ARM_THM_XPC22: + case elfcpp::R_ARM_THM_JUMP24: + reloc_status = + Arm_relocate_functions::thumb_branch_common( + r_type, relinfo, paddend, NULL, object, 0, psymval, 0, thumb_bit, + false); + break; + + case elfcpp::R_ARM_PLT32: + case elfcpp::R_ARM_CALL: + case elfcpp::R_ARM_JUMP24: + case elfcpp::R_ARM_XPC25: + reloc_status = + Arm_relocate_functions::arm_branch_common( + r_type, relinfo, paddend, NULL, object, 0, psymval, 0, thumb_bit, + false); + break; + + case elfcpp::R_ARM_THM_JUMP19: + reloc_status = + Arm_relocate_functions::thm_jump19(paddend, object, + psymval, 0, thumb_bit); + break; + + case elfcpp::R_ARM_THM_JUMP6: + reloc_status = + Arm_relocate_functions::thm_jump6(paddend, object, psymval, + 0); + break; + + case elfcpp::R_ARM_THM_JUMP8: + reloc_status = + Arm_relocate_functions::thm_jump8(paddend, object, psymval, + 0); + break; + + case elfcpp::R_ARM_THM_JUMP11: + reloc_status = + Arm_relocate_functions::thm_jump11(paddend, object, psymval, + 0); + break; + + case elfcpp::R_ARM_PREL31: + reloc_status = + Arm_relocate_functions::prel31(paddend, object, psymval, 0, + thumb_bit); + break; + + case elfcpp::R_ARM_THM_PC8: + reloc_status = + Arm_relocate_functions::thm_pc8(paddend, object, psymval, + 0); + break; + + case elfcpp::R_ARM_THM_PC12: + reloc_status = + Arm_relocate_functions::thm_pc12(paddend, object, psymval, + 0); + break; + + case elfcpp::R_ARM_THM_ALU_PREL_11_0: + reloc_status = + Arm_relocate_functions::thm_alu11(paddend, object, psymval, + 0, thumb_bit); + break; + + // These relocation truncate relocation results so we cannot handle them + // in a relocatable link. + case elfcpp::R_ARM_MOVT_ABS: + case elfcpp::R_ARM_THM_MOVT_ABS: + case elfcpp::R_ARM_MOVT_PREL: + case elfcpp::R_ARM_MOVT_BREL: + case elfcpp::R_ARM_THM_MOVT_PREL: + case elfcpp::R_ARM_THM_MOVT_BREL: + case elfcpp::R_ARM_ALU_PC_G0_NC: + case elfcpp::R_ARM_ALU_PC_G0: + case elfcpp::R_ARM_ALU_PC_G1_NC: + case elfcpp::R_ARM_ALU_PC_G1: + case elfcpp::R_ARM_ALU_PC_G2: + case elfcpp::R_ARM_ALU_SB_G0_NC: + case elfcpp::R_ARM_ALU_SB_G0: + case elfcpp::R_ARM_ALU_SB_G1_NC: + case elfcpp::R_ARM_ALU_SB_G1: + case elfcpp::R_ARM_ALU_SB_G2: + case elfcpp::R_ARM_LDR_PC_G0: + case elfcpp::R_ARM_LDR_PC_G1: + case elfcpp::R_ARM_LDR_PC_G2: + case elfcpp::R_ARM_LDR_SB_G0: + case elfcpp::R_ARM_LDR_SB_G1: + case elfcpp::R_ARM_LDR_SB_G2: + case elfcpp::R_ARM_LDRS_PC_G0: + case elfcpp::R_ARM_LDRS_PC_G1: + case elfcpp::R_ARM_LDRS_PC_G2: + case elfcpp::R_ARM_LDRS_SB_G0: + case elfcpp::R_ARM_LDRS_SB_G1: + case elfcpp::R_ARM_LDRS_SB_G2: + case elfcpp::R_ARM_LDC_PC_G0: + case elfcpp::R_ARM_LDC_PC_G1: + case elfcpp::R_ARM_LDC_PC_G2: + case elfcpp::R_ARM_LDC_SB_G0: + case elfcpp::R_ARM_LDC_SB_G1: + case elfcpp::R_ARM_LDC_SB_G2: + gold_error(_("cannot handle %s in a relocatable link"), + arp->name().c_str()); + break; + + default: + gold_unreachable(); + } + + // Report any errors. + switch (reloc_status) + { + case Arm_relocate_functions::STATUS_OKAY: + break; + case Arm_relocate_functions::STATUS_OVERFLOW: + gold_error_at_location(relinfo, relnum, reloc.get_r_offset(), + _("relocation overflow in %s"), + arp->name().c_str()); + break; + case Arm_relocate_functions::STATUS_BAD_RELOC: + gold_error_at_location(relinfo, relnum, reloc.get_r_offset(), + _("unexpected opcode while processing relocation %s"), + arp->name().c_str()); + break; + default: + gold_unreachable(); + } +} + +// Return the value to use for a dynamic symbol which requires special +// treatment. This is how we support equality comparisons of function +// pointers across shared library boundaries, as described in the +// processor specific ABI supplement. + +template +uint64_t +Target_arm::do_dynsym_value(const Symbol* gsym) const +{ + gold_assert(gsym->is_from_dynobj() && gsym->has_plt_offset()); + return this->plt_section()->address() + gsym->plt_offset(); +} + +// Map platform-specific relocs to real relocs +// +template +unsigned int +Target_arm::get_real_reloc_type(unsigned int r_type) +{ + switch (r_type) + { + case elfcpp::R_ARM_TARGET1: + // This is either R_ARM_ABS32 or R_ARM_REL32; + return elfcpp::R_ARM_ABS32; + + case elfcpp::R_ARM_TARGET2: + // This can be any reloc type but usually is R_ARM_GOT_PREL + return elfcpp::R_ARM_GOT_PREL; + + default: + return r_type; + } +} + +// Whether if two EABI versions V1 and V2 are compatible. + +template +bool +Target_arm::are_eabi_versions_compatible( + elfcpp::Elf_Word v1, + elfcpp::Elf_Word v2) +{ + // v4 and v5 are the same spec before and after it was released, + // so allow mixing them. + if ((v1 == elfcpp::EF_ARM_EABI_UNKNOWN || v2 == elfcpp::EF_ARM_EABI_UNKNOWN) + || (v1 == elfcpp::EF_ARM_EABI_VER4 && v2 == elfcpp::EF_ARM_EABI_VER5) + || (v1 == elfcpp::EF_ARM_EABI_VER5 && v2 == elfcpp::EF_ARM_EABI_VER4)) + return true; + + return v1 == v2; +} + +// Combine FLAGS from an input object called NAME and the processor-specific +// flags in the ELF header of the output. Much of this is adapted from the +// processor-specific flags merging code in elf32_arm_merge_private_bfd_data +// in bfd/elf32-arm.c. + +template +void +Target_arm::merge_processor_specific_flags( + const std::string& name, + elfcpp::Elf_Word flags) +{ + if (this->are_processor_specific_flags_set()) + { + elfcpp::Elf_Word out_flags = this->processor_specific_flags(); + + // Nothing to merge if flags equal to those in output. + if (flags == out_flags) + return; + + // Complain about various flag mismatches. + elfcpp::Elf_Word version1 = elfcpp::arm_eabi_version(flags); + elfcpp::Elf_Word version2 = elfcpp::arm_eabi_version(out_flags); + if (!this->are_eabi_versions_compatible(version1, version2) + && parameters->options().warn_mismatch()) + gold_error(_("Source object %s has EABI version %d but output has " + "EABI version %d."), + name.c_str(), + (flags & elfcpp::EF_ARM_EABIMASK) >> 24, + (out_flags & elfcpp::EF_ARM_EABIMASK) >> 24); + } + else + { + // If the input is the default architecture and had the default + // flags then do not bother setting the flags for the output + // architecture, instead allow future merges to do this. If no + // future merges ever set these flags then they will retain their + // uninitialised values, which surprise surprise, correspond + // to the default values. + if (flags == 0) + return; + + // This is the first time, just copy the flags. + // We only copy the EABI version for now. + this->set_processor_specific_flags(flags & elfcpp::EF_ARM_EABIMASK); + } +} + +// Adjust ELF file header. +template +void +Target_arm::do_adjust_elf_header( + unsigned char* view, + int len) +{ + gold_assert(len == elfcpp::Elf_sizes<32>::ehdr_size); + + elfcpp::Ehdr<32, big_endian> ehdr(view); + elfcpp::Elf_Word flags = this->processor_specific_flags(); + unsigned char e_ident[elfcpp::EI_NIDENT]; + memcpy(e_ident, ehdr.get_e_ident(), elfcpp::EI_NIDENT); + + if (elfcpp::arm_eabi_version(flags) + == elfcpp::EF_ARM_EABI_UNKNOWN) + e_ident[elfcpp::EI_OSABI] = elfcpp::ELFOSABI_ARM; + else + e_ident[elfcpp::EI_OSABI] = 0; + e_ident[elfcpp::EI_ABIVERSION] = 0; + + // FIXME: Do EF_ARM_BE8 adjustment. + + // If we're working in EABI_VER5, set the hard/soft float ABI flags + // as appropriate. + if (elfcpp::arm_eabi_version(flags) == elfcpp::EF_ARM_EABI_VER5) + { + elfcpp::Elf_Half type = ehdr.get_e_type(); + if (type == elfcpp::ET_EXEC || type == elfcpp::ET_DYN) + { + Object_attribute* attr = this->get_aeabi_object_attribute(elfcpp::Tag_ABI_VFP_args); + if (attr->int_value()) + flags |= elfcpp::EF_ARM_ABI_FLOAT_HARD; + else + flags |= elfcpp::EF_ARM_ABI_FLOAT_SOFT; + this->set_processor_specific_flags(flags); + } + } + elfcpp::Ehdr_write<32, big_endian> oehdr(view); + oehdr.put_e_ident(e_ident); +} + +// do_make_elf_object to override the same function in the base class. +// We need to use a target-specific sub-class of +// Sized_relobj_file<32, big_endian> to store ARM specific information. +// Hence we need to have our own ELF object creation. + +template +Object* +Target_arm::do_make_elf_object( + const std::string& name, + Input_file* input_file, + off_t offset, const elfcpp::Ehdr<32, big_endian>& ehdr) +{ + int et = ehdr.get_e_type(); + // ET_EXEC files are valid input for --just-symbols/-R, + // and we treat them as relocatable objects. + if (et == elfcpp::ET_REL + || (et == elfcpp::ET_EXEC && input_file->just_symbols())) + { + Arm_relobj* obj = + new Arm_relobj(name, input_file, offset, ehdr); + obj->setup(); + return obj; + } + else if (et == elfcpp::ET_DYN) + { + Sized_dynobj<32, big_endian>* obj = + new Arm_dynobj(name, input_file, offset, ehdr); + obj->setup(); + return obj; + } + else + { + gold_error(_("%s: unsupported ELF file type %d"), + name.c_str(), et); + return NULL; + } +} + +// Read the architecture from the Tag_also_compatible_with attribute, if any. +// Returns -1 if no architecture could be read. +// This is adapted from get_secondary_compatible_arch() in bfd/elf32-arm.c. + +template +int +Target_arm::get_secondary_compatible_arch( + const Attributes_section_data* pasd) +{ + const Object_attribute* known_attributes = + pasd->known_attributes(Object_attribute::OBJ_ATTR_PROC); + + // Note: the tag and its argument below are uleb128 values, though + // currently-defined values fit in one byte for each. + const std::string& sv = + known_attributes[elfcpp::Tag_also_compatible_with].string_value(); + if (sv.size() == 2 + && sv.data()[0] == elfcpp::Tag_CPU_arch + && (sv.data()[1] & 128) != 128) + return sv.data()[1]; + + // This tag is "safely ignorable", so don't complain if it looks funny. + return -1; +} + +// Set, or unset, the architecture of the Tag_also_compatible_with attribute. +// The tag is removed if ARCH is -1. +// This is adapted from set_secondary_compatible_arch() in bfd/elf32-arm.c. + +template +void +Target_arm::set_secondary_compatible_arch( + Attributes_section_data* pasd, + int arch) +{ + Object_attribute* known_attributes = + pasd->known_attributes(Object_attribute::OBJ_ATTR_PROC); + + if (arch == -1) + { + known_attributes[elfcpp::Tag_also_compatible_with].set_string_value(""); + return; + } + + // Note: the tag and its argument below are uleb128 values, though + // currently-defined values fit in one byte for each. + char sv[3]; + sv[0] = elfcpp::Tag_CPU_arch; + gold_assert(arch != 0); + sv[1] = arch; + sv[2] = '\0'; + + known_attributes[elfcpp::Tag_also_compatible_with].set_string_value(sv); +} + +// Combine two values for Tag_CPU_arch, taking secondary compatibility tags +// into account. +// This is adapted from tag_cpu_arch_combine() in bfd/elf32-arm.c. + +template +int +Target_arm::tag_cpu_arch_combine( + const char* name, + int oldtag, + int* secondary_compat_out, + int newtag, + int secondary_compat) +{ +#define T(X) elfcpp::TAG_CPU_ARCH_##X + static const int v6t2[] = + { + T(V6T2), // PRE_V4. + T(V6T2), // V4. + T(V6T2), // V4T. + T(V6T2), // V5T. + T(V6T2), // V5TE. + T(V6T2), // V5TEJ. + T(V6T2), // V6. + T(V7), // V6KZ. + T(V6T2) // V6T2. + }; + static const int v6k[] = + { + T(V6K), // PRE_V4. + T(V6K), // V4. + T(V6K), // V4T. + T(V6K), // V5T. + T(V6K), // V5TE. + T(V6K), // V5TEJ. + T(V6K), // V6. + T(V6KZ), // V6KZ. + T(V7), // V6T2. + T(V6K) // V6K. + }; + static const int v7[] = + { + T(V7), // PRE_V4. + T(V7), // V4. + T(V7), // V4T. + T(V7), // V5T. + T(V7), // V5TE. + T(V7), // V5TEJ. + T(V7), // V6. + T(V7), // V6KZ. + T(V7), // V6T2. + T(V7), // V6K. + T(V7) // V7. + }; + static const int v6_m[] = + { + -1, // PRE_V4. + -1, // V4. + T(V6K), // V4T. + T(V6K), // V5T. + T(V6K), // V5TE. + T(V6K), // V5TEJ. + T(V6K), // V6. + T(V6KZ), // V6KZ. + T(V7), // V6T2. + T(V6K), // V6K. + T(V7), // V7. + T(V6_M) // V6_M. + }; + static const int v6s_m[] = + { + -1, // PRE_V4. + -1, // V4. + T(V6K), // V4T. + T(V6K), // V5T. + T(V6K), // V5TE. + T(V6K), // V5TEJ. + T(V6K), // V6. + T(V6KZ), // V6KZ. + T(V7), // V6T2. + T(V6K), // V6K. + T(V7), // V7. + T(V6S_M), // V6_M. + T(V6S_M) // V6S_M. + }; + static const int v7e_m[] = + { + -1, // PRE_V4. + -1, // V4. + T(V7E_M), // V4T. + T(V7E_M), // V5T. + T(V7E_M), // V5TE. + T(V7E_M), // V5TEJ. + T(V7E_M), // V6. + T(V7E_M), // V6KZ. + T(V7E_M), // V6T2. + T(V7E_M), // V6K. + T(V7E_M), // V7. + T(V7E_M), // V6_M. + T(V7E_M), // V6S_M. + T(V7E_M) // V7E_M. + }; + static const int v4t_plus_v6_m[] = + { + -1, // PRE_V4. + -1, // V4. + T(V4T), // V4T. + T(V5T), // V5T. + T(V5TE), // V5TE. + T(V5TEJ), // V5TEJ. + T(V6), // V6. + T(V6KZ), // V6KZ. + T(V6T2), // V6T2. + T(V6K), // V6K. + T(V7), // V7. + T(V6_M), // V6_M. + T(V6S_M), // V6S_M. + T(V7E_M), // V7E_M. + T(V4T_PLUS_V6_M) // V4T plus V6_M. + }; + static const int* comb[] = + { + v6t2, + v6k, + v7, + v6_m, + v6s_m, + v7e_m, + // Pseudo-architecture. + v4t_plus_v6_m + }; + + // Check we've not got a higher architecture than we know about. + + if (oldtag > elfcpp::MAX_TAG_CPU_ARCH || newtag > elfcpp::MAX_TAG_CPU_ARCH) + { + gold_error(_("%s: unknown CPU architecture"), name); + return -1; + } + + // Override old tag if we have a Tag_also_compatible_with on the output. + + if ((oldtag == T(V6_M) && *secondary_compat_out == T(V4T)) + || (oldtag == T(V4T) && *secondary_compat_out == T(V6_M))) + oldtag = T(V4T_PLUS_V6_M); + + // And override the new tag if we have a Tag_also_compatible_with on the + // input. + + if ((newtag == T(V6_M) && secondary_compat == T(V4T)) + || (newtag == T(V4T) && secondary_compat == T(V6_M))) + newtag = T(V4T_PLUS_V6_M); + + // Architectures before V6KZ add features monotonically. + int tagh = std::max(oldtag, newtag); + if (tagh <= elfcpp::TAG_CPU_ARCH_V6KZ) + return tagh; + + int tagl = std::min(oldtag, newtag); + int result = comb[tagh - T(V6T2)][tagl]; + + // Use Tag_CPU_arch == V4T and Tag_also_compatible_with (Tag_CPU_arch V6_M) + // as the canonical version. + if (result == T(V4T_PLUS_V6_M)) + { + result = T(V4T); + *secondary_compat_out = T(V6_M); + } + else + *secondary_compat_out = -1; + + if (result == -1) + { + gold_error(_("%s: conflicting CPU architectures %d/%d"), + name, oldtag, newtag); + return -1; + } + + return result; +#undef T +} + +// Helper to print AEABI enum tag value. + +template +std::string +Target_arm::aeabi_enum_name(unsigned int value) +{ + static const char* aeabi_enum_names[] = + { "", "variable-size", "32-bit", "" }; + const size_t aeabi_enum_names_size = + sizeof(aeabi_enum_names) / sizeof(aeabi_enum_names[0]); + + if (value < aeabi_enum_names_size) + return std::string(aeabi_enum_names[value]); + else + { + char buffer[100]; + sprintf(buffer, "", value); + return std::string(buffer); + } +} + +// Return the string value to store in TAG_CPU_name. + +template +std::string +Target_arm::tag_cpu_name_value(unsigned int value) +{ + static const char* name_table[] = { + // These aren't real CPU names, but we can't guess + // that from the architecture version alone. + "Pre v4", + "ARM v4", + "ARM v4T", + "ARM v5T", + "ARM v5TE", + "ARM v5TEJ", + "ARM v6", + "ARM v6KZ", + "ARM v6T2", + "ARM v6K", + "ARM v7", + "ARM v6-M", + "ARM v6S-M", + "ARM v7E-M" + }; + const size_t name_table_size = sizeof(name_table) / sizeof(name_table[0]); + + if (value < name_table_size) + return std::string(name_table[value]); + else + { + char buffer[100]; + sprintf(buffer, "", value); + return std::string(buffer); + } +} + +// Query attributes object to see if integer divide instructions may be +// present in an object. + +template +bool +Target_arm::attributes_accept_div(int arch, int profile, + const Object_attribute* div_attr) +{ + switch (div_attr->int_value()) + { + case 0: + // Integer divide allowed if instruction contained in + // archetecture. + if (arch == elfcpp::TAG_CPU_ARCH_V7 && (profile == 'R' || profile == 'M')) + return true; + else if (arch >= elfcpp::TAG_CPU_ARCH_V7E_M) + return true; + else + return false; + + case 1: + // Integer divide explicitly prohibited. + return false; + + default: + // Unrecognised case - treat as allowing divide everywhere. + case 2: + // Integer divide allowed in ARM state. + return true; + } +} + +// Query attributes object to see if integer divide instructions are +// forbidden to be in the object. This is not the inverse of +// attributes_accept_div. + +template +bool +Target_arm::attributes_forbid_div(const Object_attribute* div_attr) +{ + return div_attr->int_value() == 1; +} + +// Merge object attributes from input file called NAME with those of the +// output. The input object attributes are in the object pointed by PASD. + +template +void +Target_arm::merge_object_attributes( + const char* name, + const Attributes_section_data* pasd) +{ + // Return if there is no attributes section data. + if (pasd == NULL) + return; + + // If output has no object attributes, just copy. + const int vendor = Object_attribute::OBJ_ATTR_PROC; + if (this->attributes_section_data_ == NULL) + { + this->attributes_section_data_ = new Attributes_section_data(*pasd); + Object_attribute* out_attr = + this->attributes_section_data_->known_attributes(vendor); + + // We do not output objects with Tag_MPextension_use_legacy - we move + // the attribute's value to Tag_MPextension_use. */ + if (out_attr[elfcpp::Tag_MPextension_use_legacy].int_value() != 0) + { + 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()) + { + gold_error(_("%s has both the current and legacy " + "Tag_MPextension_use attributes"), + name); + } + + out_attr[elfcpp::Tag_MPextension_use] = + out_attr[elfcpp::Tag_MPextension_use_legacy]; + out_attr[elfcpp::Tag_MPextension_use_legacy].set_type(0); + out_attr[elfcpp::Tag_MPextension_use_legacy].set_int_value(0); + } + + return; + } + + const Object_attribute* in_attr = pasd->known_attributes(vendor); + Object_attribute* out_attr = + this->attributes_section_data_->known_attributes(vendor); + + // This needs to happen before Tag_ABI_FP_number_model is merged. */ + if (in_attr[elfcpp::Tag_ABI_VFP_args].int_value() + != out_attr[elfcpp::Tag_ABI_VFP_args].int_value()) + { + // Ignore mismatches if the object doesn't use floating point. */ + if (out_attr[elfcpp::Tag_ABI_FP_number_model].int_value() == 0) + out_attr[elfcpp::Tag_ABI_VFP_args].set_int_value( + 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"), + name); + } + + for (int i = 4; i < Vendor_object_attributes::NUM_KNOWN_ATTRIBUTES; ++i) + { + // Merge this attribute with existing attributes. + switch (i) + { + case elfcpp::Tag_CPU_raw_name: + case elfcpp::Tag_CPU_name: + // These are merged after Tag_CPU_arch. + break; + + case elfcpp::Tag_ABI_optimization_goals: + case elfcpp::Tag_ABI_FP_optimization_goals: + // Use the first value seen. + break; + + case elfcpp::Tag_CPU_arch: + { + unsigned int saved_out_attr = out_attr->int_value(); + // Merge Tag_CPU_arch and Tag_also_compatible_with. + int secondary_compat = + this->get_secondary_compatible_arch(pasd); + int secondary_compat_out = + this->get_secondary_compatible_arch( + this->attributes_section_data_); + out_attr[i].set_int_value( + tag_cpu_arch_combine(name, out_attr[i].int_value(), + &secondary_compat_out, + in_attr[i].int_value(), + secondary_compat)); + this->set_secondary_compatible_arch(this->attributes_section_data_, + secondary_compat_out); + + // Merge Tag_CPU_name and Tag_CPU_raw_name. + if (out_attr[i].int_value() == saved_out_attr) + ; // Leave the names alone. + else if (out_attr[i].int_value() == in_attr[i].int_value()) + { + // The output architecture has been changed to match the + // input architecture. Use the input names. + out_attr[elfcpp::Tag_CPU_name].set_string_value( + in_attr[elfcpp::Tag_CPU_name].string_value()); + out_attr[elfcpp::Tag_CPU_raw_name].set_string_value( + in_attr[elfcpp::Tag_CPU_raw_name].string_value()); + } + else + { + out_attr[elfcpp::Tag_CPU_name].set_string_value(""); + out_attr[elfcpp::Tag_CPU_raw_name].set_string_value(""); + } + + // If we still don't have a value for Tag_CPU_name, + // make one up now. Tag_CPU_raw_name remains blank. + if (out_attr[elfcpp::Tag_CPU_name].string_value() == "") + { + const std::string cpu_name = + this->tag_cpu_name_value(out_attr[i].int_value()); + // FIXME: If we see an unknown CPU, this will be set + // to "", where n is the attribute value. + // This is different from BFD, which leaves the name alone. + out_attr[elfcpp::Tag_CPU_name].set_string_value(cpu_name); + } + } + break; + + case elfcpp::Tag_ARM_ISA_use: + case elfcpp::Tag_THUMB_ISA_use: + case elfcpp::Tag_WMMX_arch: + case elfcpp::Tag_Advanced_SIMD_arch: + // ??? Do Advanced_SIMD (NEON) and WMMX conflict? + case elfcpp::Tag_ABI_FP_rounding: + case elfcpp::Tag_ABI_FP_exceptions: + case elfcpp::Tag_ABI_FP_user_exceptions: + case elfcpp::Tag_ABI_FP_number_model: + case elfcpp::Tag_VFP_HP_extension: + case elfcpp::Tag_CPU_unaligned_access: + case elfcpp::Tag_T2EE_use: + case elfcpp::Tag_Virtualization_use: + case elfcpp::Tag_MPextension_use: + // Use the largest value specified. + if (in_attr[i].int_value() > out_attr[i].int_value()) + out_attr[i].set_int_value(in_attr[i].int_value()); + break; + + case elfcpp::Tag_ABI_align8_preserved: + case elfcpp::Tag_ABI_PCS_RO_data: + // Use the smallest value specified. + if (in_attr[i].int_value() < out_attr[i].int_value()) + out_attr[i].set_int_value(in_attr[i].int_value()); + break; + + case elfcpp::Tag_ABI_align8_needed: + if ((in_attr[i].int_value() > 0 || out_attr[i].int_value() > 0) + && (in_attr[elfcpp::Tag_ABI_align8_preserved].int_value() == 0 + || (out_attr[elfcpp::Tag_ABI_align8_preserved].int_value() + == 0))) + { + // This error message should be enabled once all non-conforming + // binaries in the toolchain have had the attributes set + // properly. + // gold_error(_("output 8-byte data alignment conflicts with %s"), + // name); + } + // Fall through. + case elfcpp::Tag_ABI_FP_denormal: + case elfcpp::Tag_ABI_PCS_GOT_use: + { + // These tags have 0 = don't care, 1 = strong requirement, + // 2 = weak requirement. + static const int order_021[3] = {0, 2, 1}; + + // Use the "greatest" from the sequence 0, 2, 1, or the largest + // value if greater than 2 (for future-proofing). + if ((in_attr[i].int_value() > 2 + && in_attr[i].int_value() > out_attr[i].int_value()) + || (in_attr[i].int_value() <= 2 + && out_attr[i].int_value() <= 2 + && (order_021[in_attr[i].int_value()] + > order_021[out_attr[i].int_value()]))) + out_attr[i].set_int_value(in_attr[i].int_value()); + } + break; + + case elfcpp::Tag_CPU_arch_profile: + if (out_attr[i].int_value() != in_attr[i].int_value()) + { + // 0 will merge with anything. + // 'A' and 'S' merge to 'A'. + // 'R' and 'S' merge to 'R'. + // 'M' and 'A|R|S' is an error. + if (out_attr[i].int_value() == 0 + || (out_attr[i].int_value() == 'S' + && (in_attr[i].int_value() == 'A' + || in_attr[i].int_value() == 'R'))) + out_attr[i].set_int_value(in_attr[i].int_value()); + else if (in_attr[i].int_value() == 0 + || (in_attr[i].int_value() == 'S' + && (out_attr[i].int_value() == 'A' + || out_attr[i].int_value() == 'R'))) + ; // Do nothing. + else if (parameters->options().warn_mismatch()) + { + gold_error + (_("conflicting architecture profiles %c/%c"), + in_attr[i].int_value() ? in_attr[i].int_value() : '0', + out_attr[i].int_value() ? out_attr[i].int_value() : '0'); + } + } + break; + case elfcpp::Tag_VFP_arch: + { + static const struct + { + int ver; + int regs; + } vfp_versions[7] = + { + {0, 0}, + {1, 16}, + {2, 16}, + {3, 32}, + {3, 16}, + {4, 32}, + {4, 16} + }; + + // Values greater than 6 aren't defined, so just pick the + // biggest. + if (in_attr[i].int_value() > 6 + && in_attr[i].int_value() > out_attr[i].int_value()) + { + *out_attr = *in_attr; + break; + } + // The output uses the superset of input features + // (ISA version) and registers. + int ver = std::max(vfp_versions[in_attr[i].int_value()].ver, + vfp_versions[out_attr[i].int_value()].ver); + int regs = std::max(vfp_versions[in_attr[i].int_value()].regs, + vfp_versions[out_attr[i].int_value()].regs); + // This assumes all possible supersets are also a valid + // options. + int newval; + for (newval = 6; newval > 0; newval--) + { + if (regs == vfp_versions[newval].regs + && ver == vfp_versions[newval].ver) + break; + } + out_attr[i].set_int_value(newval); + } + break; + case elfcpp::Tag_PCS_config: + if (out_attr[i].int_value() == 0) + out_attr[i].set_int_value(in_attr[i].int_value()); + else if (in_attr[i].int_value() != 0 + && out_attr[i].int_value() != 0 + && parameters->options().warn_mismatch()) + { + // It's sometimes ok to mix different configs, so this is only + // a warning. + gold_warning(_("%s: conflicting platform configuration"), name); + } + break; + case elfcpp::Tag_ABI_PCS_R9_use: + if (in_attr[i].int_value() != out_attr[i].int_value() + && out_attr[i].int_value() != elfcpp::AEABI_R9_unused + && in_attr[i].int_value() != elfcpp::AEABI_R9_unused + && parameters->options().warn_mismatch()) + { + gold_error(_("%s: conflicting use of R9"), name); + } + if (out_attr[i].int_value() == elfcpp::AEABI_R9_unused) + out_attr[i].set_int_value(in_attr[i].int_value()); + break; + case elfcpp::Tag_ABI_PCS_RW_data: + if (in_attr[i].int_value() == elfcpp::AEABI_PCS_RW_data_SBrel + && (in_attr[elfcpp::Tag_ABI_PCS_R9_use].int_value() + != elfcpp::AEABI_R9_SB) + && (out_attr[elfcpp::Tag_ABI_PCS_R9_use].int_value() + != elfcpp::AEABI_R9_unused) + && parameters->options().warn_mismatch()) + { + gold_error(_("%s: SB relative addressing conflicts with use " + "of R9"), + name); + } + // Use the smallest value specified. + if (in_attr[i].int_value() < out_attr[i].int_value()) + out_attr[i].set_int_value(in_attr[i].int_value()); + break; + case elfcpp::Tag_ABI_PCS_wchar_t: + if (out_attr[i].int_value() + && in_attr[i].int_value() + && out_attr[i].int_value() != in_attr[i].int_value() + && parameters->options().warn_mismatch() + && parameters->options().wchar_size_warning()) + { + gold_warning(_("%s uses %u-byte wchar_t yet the output is to " + "use %u-byte wchar_t; use of wchar_t values " + "across objects may fail"), + name, in_attr[i].int_value(), + out_attr[i].int_value()); + } + else if (in_attr[i].int_value() && !out_attr[i].int_value()) + out_attr[i].set_int_value(in_attr[i].int_value()); + break; + case elfcpp::Tag_ABI_enum_size: + if (in_attr[i].int_value() != elfcpp::AEABI_enum_unused) + { + if (out_attr[i].int_value() == elfcpp::AEABI_enum_unused + || out_attr[i].int_value() == elfcpp::AEABI_enum_forced_wide) + { + // The existing object is compatible with anything. + // Use whatever requirements the new object has. + out_attr[i].set_int_value(in_attr[i].int_value()); + } + else if (in_attr[i].int_value() != elfcpp::AEABI_enum_forced_wide + && out_attr[i].int_value() != in_attr[i].int_value() + && parameters->options().warn_mismatch() + && parameters->options().enum_size_warning()) + { + unsigned int in_value = in_attr[i].int_value(); + unsigned int out_value = out_attr[i].int_value(); + gold_warning(_("%s uses %s enums yet the output is to use " + "%s enums; use of enum values across objects " + "may fail"), + name, + this->aeabi_enum_name(in_value).c_str(), + this->aeabi_enum_name(out_value).c_str()); + } + } + break; + case elfcpp::Tag_ABI_VFP_args: + // Already done. + break; + case elfcpp::Tag_ABI_WMMX_args: + if (in_attr[i].int_value() != out_attr[i].int_value() + && parameters->options().warn_mismatch()) + { + gold_error(_("%s uses iWMMXt register arguments, output does " + "not"), + name); + } + break; + case Object_attribute::Tag_compatibility: + // Merged in target-independent code. + break; + case elfcpp::Tag_ABI_HardFP_use: + // 1 (SP) and 2 (DP) conflict, so combine to 3 (SP & DP). + if ((in_attr[i].int_value() == 1 && out_attr[i].int_value() == 2) + || (in_attr[i].int_value() == 2 && out_attr[i].int_value() == 1)) + out_attr[i].set_int_value(3); + else if (in_attr[i].int_value() > out_attr[i].int_value()) + out_attr[i].set_int_value(in_attr[i].int_value()); + break; + case elfcpp::Tag_ABI_FP_16bit_format: + if (in_attr[i].int_value() != 0 && out_attr[i].int_value() != 0) + { + if (in_attr[i].int_value() != out_attr[i].int_value() + && parameters->options().warn_mismatch()) + gold_error(_("fp16 format mismatch between %s and output"), + name); + } + if (in_attr[i].int_value() != 0) + out_attr[i].set_int_value(in_attr[i].int_value()); + break; + + case elfcpp::Tag_DIV_use: + { + // A value of zero on input means that the divide + // instruction may be used if available in the base + // architecture as specified via Tag_CPU_arch and + // Tag_CPU_arch_profile. A value of 1 means that the user + // did not want divide instructions. A value of 2 + // explicitly means that divide instructions were allowed + // in ARM and Thumb state. + int arch = this-> + get_aeabi_object_attribute(elfcpp::Tag_CPU_arch)-> + int_value(); + int profile = this-> + get_aeabi_object_attribute(elfcpp::Tag_CPU_arch_profile)-> + int_value(); + if (in_attr[i].int_value() == out_attr[i].int_value()) + { + // Do nothing. + } + else if (attributes_forbid_div(&in_attr[i]) + && !attributes_accept_div(arch, profile, &out_attr[i])) + out_attr[i].set_int_value(1); + else if (attributes_forbid_div(&out_attr[i]) + && attributes_accept_div(arch, profile, &in_attr[i])) + out_attr[i].set_int_value(in_attr[i].int_value()); + else if (in_attr[i].int_value() == 2) + out_attr[i].set_int_value(in_attr[i].int_value()); + } + break; + + case elfcpp::Tag_MPextension_use_legacy: + // We don't output objects with Tag_MPextension_use_legacy - we + // move the value to Tag_MPextension_use. + if (in_attr[i].int_value() != 0 + && in_attr[elfcpp::Tag_MPextension_use].int_value() != 0) + { + if (in_attr[elfcpp::Tag_MPextension_use].int_value() + != in_attr[i].int_value()) + { + gold_error(_("%s has has both the current and legacy " + "Tag_MPextension_use attributes"), + name); + } + } + + if (in_attr[i].int_value() + > out_attr[elfcpp::Tag_MPextension_use].int_value()) + out_attr[elfcpp::Tag_MPextension_use] = in_attr[i]; + + break; + + case elfcpp::Tag_nodefaults: + // This tag is set if it exists, but the value is unused (and is + // typically zero). We don't actually need to do anything here - + // the merge happens automatically when the type flags are merged + // below. + break; + case elfcpp::Tag_also_compatible_with: + // Already done in Tag_CPU_arch. + break; + case elfcpp::Tag_conformance: + // Keep the attribute if it matches. Throw it away otherwise. + // No attribute means no claim to conform. + if (in_attr[i].string_value() != out_attr[i].string_value()) + out_attr[i].set_string_value(""); + break; + + default: + { + const char* err_object = NULL; + + // The "known_obj_attributes" table does contain some undefined + // attributes. Ensure that there are unused. + if (out_attr[i].int_value() != 0 + || out_attr[i].string_value() != "") + err_object = "output"; + else if (in_attr[i].int_value() != 0 + || in_attr[i].string_value() != "") + err_object = name; + + if (err_object != NULL + && parameters->options().warn_mismatch()) + { + // Attribute numbers >=64 (mod 128) can be safely ignored. + if ((i & 127) < 64) + gold_error(_("%s: unknown mandatory EABI object attribute " + "%d"), + err_object, i); + else + gold_warning(_("%s: unknown EABI object attribute %d"), + err_object, i); + } + + // Only pass on attributes that match in both inputs. + if (!in_attr[i].matches(out_attr[i])) + { + out_attr[i].set_int_value(0); + out_attr[i].set_string_value(""); + } + } + } + + // If out_attr was copied from in_attr then it won't have a type yet. + if (in_attr[i].type() && !out_attr[i].type()) + out_attr[i].set_type(in_attr[i].type()); + } + + // Merge Tag_compatibility attributes and any common GNU ones. + this->attributes_section_data_->merge(name, pasd); + + // Check for any attributes not known on ARM. + typedef Vendor_object_attributes::Other_attributes Other_attributes; + const Other_attributes* in_other_attributes = pasd->other_attributes(vendor); + Other_attributes::const_iterator in_iter = in_other_attributes->begin(); + Other_attributes* out_other_attributes = + this->attributes_section_data_->other_attributes(vendor); + Other_attributes::iterator out_iter = out_other_attributes->begin(); + + while (in_iter != in_other_attributes->end() + || out_iter != out_other_attributes->end()) + { + const char* err_object = NULL; + int err_tag = 0; + + // The tags for each list are in numerical order. + // If the tags are equal, then merge. + if (out_iter != out_other_attributes->end() + && (in_iter == in_other_attributes->end() + || in_iter->first > out_iter->first)) + { + // This attribute only exists in output. We can't merge, and we + // don't know what the tag means, so delete it. + err_object = "output"; + err_tag = out_iter->first; + int saved_tag = out_iter->first; + delete out_iter->second; + out_other_attributes->erase(out_iter); + out_iter = out_other_attributes->upper_bound(saved_tag); + } + else if (in_iter != in_other_attributes->end() + && (out_iter != out_other_attributes->end() + || in_iter->first < out_iter->first)) + { + // This attribute only exists in input. We can't merge, and we + // don't know what the tag means, so ignore it. + err_object = name; + err_tag = in_iter->first; + ++in_iter; + } + else // The tags are equal. + { + // As present, all attributes in the list are unknown, and + // therefore can't be merged meaningfully. + err_object = "output"; + err_tag = out_iter->first; + + // Only pass on attributes that match in both inputs. + if (!in_iter->second->matches(*(out_iter->second))) + { + // No match. Delete the attribute. + int saved_tag = out_iter->first; + delete out_iter->second; + out_other_attributes->erase(out_iter); + out_iter = out_other_attributes->upper_bound(saved_tag); + } + else + { + // Matched. Keep the attribute and move to the next. + ++out_iter; + ++in_iter; + } + } + + if (err_object && parameters->options().warn_mismatch()) + { + // Attribute numbers >=64 (mod 128) can be safely ignored. */ + if ((err_tag & 127) < 64) + { + gold_error(_("%s: unknown mandatory EABI object attribute %d"), + err_object, err_tag); + } + else + { + gold_warning(_("%s: unknown EABI object attribute %d"), + err_object, err_tag); + } + } + } +} + +// Stub-generation methods for Target_arm. + +// Make a new Arm_input_section object. + +template +Arm_input_section* +Target_arm::new_arm_input_section( + Relobj* relobj, + unsigned int shndx) +{ + Section_id sid(relobj, shndx); + + Arm_input_section* arm_input_section = + new Arm_input_section(relobj, shndx); + arm_input_section->init(); + + // Register new Arm_input_section in map for look-up. + std::pair ins = + this->arm_input_section_map_.insert(std::make_pair(sid, arm_input_section)); + + // Make sure that it we have not created another Arm_input_section + // for this input section already. + gold_assert(ins.second); + + return arm_input_section; +} + +// Find the Arm_input_section object corresponding to the SHNDX-th input +// section of RELOBJ. + +template +Arm_input_section* +Target_arm::find_arm_input_section( + Relobj* relobj, + unsigned int shndx) const +{ + Section_id sid(relobj, shndx); + typename Arm_input_section_map::const_iterator p = + this->arm_input_section_map_.find(sid); + return (p != this->arm_input_section_map_.end()) ? p->second : NULL; +} + +// Make a new stub table. + +template +Stub_table* +Target_arm::new_stub_table(Arm_input_section* owner) +{ + Stub_table* stub_table = + new Stub_table(owner); + this->stub_tables_.push_back(stub_table); + + stub_table->set_address(owner->address() + owner->data_size()); + stub_table->set_file_offset(owner->offset() + owner->data_size()); + stub_table->finalize_data_size(); + + return stub_table; +} + +// Scan a relocation for stub generation. + +template +void +Target_arm::scan_reloc_for_stub( + const Relocate_info<32, big_endian>* relinfo, + unsigned int r_type, + const Sized_symbol<32>* gsym, + unsigned int r_sym, + const Symbol_value<32>* psymval, + elfcpp::Elf_types<32>::Elf_Swxword addend, + Arm_address address) +{ + const Arm_relobj* arm_relobj = + Arm_relobj::as_arm_relobj(relinfo->object); + + bool target_is_thumb; + Symbol_value<32> symval; + if (gsym != NULL) + { + // This is a global symbol. Determine if we use PLT and if the + // final target is THUMB. + if (gsym->use_plt_offset(Scan::get_reference_flags(r_type))) + { + // This uses a PLT, change the symbol value. + symval.set_output_value(this->plt_section()->address() + + gsym->plt_offset()); + psymval = &symval; + target_is_thumb = false; + } + else if (gsym->is_undefined()) + // There is no need to generate a stub symbol is undefined. + return; + else + { + target_is_thumb = + ((gsym->type() == elfcpp::STT_ARM_TFUNC) + || (gsym->type() == elfcpp::STT_FUNC + && !gsym->is_undefined() + && ((psymval->value(arm_relobj, 0) & 1) != 0))); + } + } + else + { + // This is a local symbol. Determine if the final target is THUMB. + target_is_thumb = arm_relobj->local_symbol_is_thumb_function(r_sym); + } + + // Strip LSB if this points to a THUMB target. + const Arm_reloc_property* reloc_property = + arm_reloc_property_table->get_implemented_static_reloc_property(r_type); + gold_assert(reloc_property != NULL); + if (target_is_thumb + && reloc_property->uses_thumb_bit() + && ((psymval->value(arm_relobj, 0) & 1) != 0)) + { + Arm_address stripped_value = + psymval->value(arm_relobj, 0) & ~static_cast(1); + symval.set_output_value(stripped_value); + psymval = &symval; + } + + // Get the symbol value. + Symbol_value<32>::Value value = psymval->value(arm_relobj, 0); + + // Owing to pipelining, the PC relative branches below actually skip + // two instructions when the branch offset is 0. + Arm_address destination; + switch (r_type) + { + case elfcpp::R_ARM_CALL: + case elfcpp::R_ARM_JUMP24: + case elfcpp::R_ARM_PLT32: + // ARM branches. + destination = value + addend + 8; + break; + case elfcpp::R_ARM_THM_CALL: + case elfcpp::R_ARM_THM_XPC22: + case elfcpp::R_ARM_THM_JUMP24: + case elfcpp::R_ARM_THM_JUMP19: + // THUMB branches. + destination = value + addend + 4; + break; + default: + gold_unreachable(); + } + + Reloc_stub* stub = NULL; + Stub_type stub_type = + Reloc_stub::stub_type_for_reloc(r_type, address, destination, + target_is_thumb); + if (stub_type != arm_stub_none) + { + // Try looking up an existing stub from a stub table. + Stub_table* 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); + + // Create a stub if there is not one already + stub = stub_table->find_reloc_stub(stub_key); + if (stub == NULL) + { + // create a new stub and add it to stub table. + stub = this->stub_factory().make_reloc_stub(stub_type); + stub_table->add_reloc_stub(stub, stub_key); + } + + // Record the destination address. + stub->set_destination_address(destination + | (target_is_thumb ? 1 : 0)); + } + + // For Cortex-A8, we need to record a relocation at 4K page boundary. + if (this->fix_cortex_a8_ + && (r_type == elfcpp::R_ARM_THM_JUMP24 + || r_type == elfcpp::R_ARM_THM_JUMP19 + || r_type == elfcpp::R_ARM_THM_CALL + || r_type == elfcpp::R_ARM_THM_XPC22) + && (address & 0xfffU) == 0xffeU) + { + // Found a candidate. Note we haven't checked the destination is + // within 4K here: if we do so (and don't create a record) we can't + // tell that a branch should have been relocated when scanning later. + this->cortex_a8_relocs_info_[address] = + new Cortex_a8_reloc(stub, r_type, + destination | (target_is_thumb ? 1 : 0)); + } +} + +// This function scans a relocation sections for stub generation. +// The template parameter Relocate must be a class type which provides +// a single function, relocate(), which implements the machine +// specific part of a relocation. + +// BIG_ENDIAN is the endianness of the data. SH_TYPE is the section type: +// SHT_REL or SHT_RELA. + +// PRELOCS points to the relocation data. RELOC_COUNT is the number +// of relocs. OUTPUT_SECTION is the output section. +// NEEDS_SPECIAL_OFFSET_HANDLING is true if input offsets need to be +// mapped to output offsets. + +// VIEW is the section data, VIEW_ADDRESS is its memory address, and +// VIEW_SIZE is the size. These refer to the input section, unless +// NEEDS_SPECIAL_OFFSET_HANDLING is true, in which case they refer to +// the output section. + +template +template +void inline +Target_arm::scan_reloc_section_for_stubs( + const Relocate_info<32, big_endian>* relinfo, + const unsigned char* prelocs, + size_t reloc_count, + Output_section* output_section, + bool needs_special_offset_handling, + const unsigned char* view, + elfcpp::Elf_types<32>::Elf_Addr view_address, + section_size_type) +{ + typedef typename Reloc_types::Reloc Reltype; + const int reloc_size = + Reloc_types::reloc_size; + + Arm_relobj* arm_object = + Arm_relobj::as_arm_relobj(relinfo->object); + unsigned int local_count = arm_object->local_symbol_count(); + + gold::Default_comdat_behavior default_comdat_behavior; + Comdat_behavior comdat_behavior = CB_UNDETERMINED; + + for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size) + { + Reltype reloc(prelocs); + + typename elfcpp::Elf_types<32>::Elf_WXword r_info = reloc.get_r_info(); + unsigned int r_sym = elfcpp::elf_r_sym<32>(r_info); + unsigned int r_type = elfcpp::elf_r_type<32>(r_info); + + r_type = this->get_real_reloc_type(r_type); + + // 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)) + continue; + + section_offset_type offset = + convert_to_section_size_type(reloc.get_r_offset()); + + if (needs_special_offset_handling) + { + offset = output_section->output_offset(relinfo->object, + relinfo->data_shndx, + offset); + if (offset == -1) + continue; + } + + // Create a v4bx stub if --fix-v4bx-interworking is used. + if (r_type == elfcpp::R_ARM_V4BX) + { + if (this->fix_v4bx() == General_options::FIX_V4BX_INTERWORKING) + { + // Get the BX instruction. + typedef typename elfcpp::Swap<32, big_endian>::Valtype Valtype; + const Valtype* wv = + reinterpret_cast(view + offset); + elfcpp::Elf_types<32>::Elf_Swxword insn = + elfcpp::Swap<32, big_endian>::readval(wv); + const uint32_t reg = (insn & 0xf); + + if (reg < 0xf) + { + // Try looking up an existing stub from a stub table. + Stub_table* stub_table = + arm_object->stub_table(relinfo->data_shndx); + gold_assert(stub_table != NULL); + + if (stub_table->find_arm_v4bx_stub(reg) == NULL) + { + // create a new stub and add it to stub table. + Arm_v4bx_stub* stub = + this->stub_factory().make_arm_v4bx_stub(reg); + gold_assert(stub != NULL); + stub_table->add_arm_v4bx_stub(stub); + } + } + } + continue; + } + + // Get the addend. + Stub_addend_reader stub_addend_reader; + elfcpp::Elf_types<32>::Elf_Swxword addend = + stub_addend_reader(r_type, view + offset, reloc); + + const Sized_symbol<32>* sym; + + Symbol_value<32> symval; + const Symbol_value<32> *psymval; + bool is_defined_in_discarded_section; + unsigned int shndx; + if (r_sym < local_count) + { + 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. + bool is_ordinary; + shndx = psymval->input_shndx(&is_ordinary); + is_defined_in_discarded_section = + (is_ordinary + && shndx != elfcpp::SHN_UNDEF + && !arm_object->is_section_included(shndx) + && !relinfo->symtab->is_section_folded(arm_object, shndx)); + + // We need to compute the would-be final value of this local + // symbol. + if (!is_defined_in_discarded_section) + { + typedef Sized_relobj_file<32, big_endian> ObjType; + typename ObjType::Compute_final_local_value_status status = + arm_object->compute_final_local_value(r_sym, psymval, &symval, + relinfo->symtab); + if (status == ObjType::CFLV_OK) + { + // Currently we cannot handle a branch to a target in + // a merged section. If this is the case, issue an error + // and also free the merge symbol value. + if (!symval.has_output_value()) + { + const std::string& section_name = + arm_object->section_name(shndx); + arm_object->error(_("cannot handle branch to local %u " + "in a merged section %s"), + r_sym, section_name.c_str()); + } + psymval = &symval; + } + else + { + // We cannot determine the final value. + continue; + } + } + } + else + { + const Symbol* gsym; + gsym = arm_object->global_symbol(r_sym); + gold_assert(gsym != NULL); + if (gsym->is_forwarder()) + gsym = relinfo->symtab->resolve_forwards(gsym); + + sym = static_cast*>(gsym); + if (sym->has_symtab_index() && sym->symtab_index() != -1U) + symval.set_output_symtab_index(sym->symtab_index()); + else + symval.set_no_output_symtab_entry(); + + // We need to compute the would-be final value of this global + // symbol. + const Symbol_table* symtab = relinfo->symtab; + const Sized_symbol<32>* sized_symbol = + symtab->get_sized_symbol<32>(gsym); + Symbol_table::Compute_final_value_status status; + Arm_address value = + symtab->compute_final_value<32>(sized_symbol, &status); + + // Skip this if the symbol has not output section. + if (status == Symbol_table::CFVS_NO_OUTPUT_SECTION) + continue; + symval.set_output_value(value); + + if (gsym->type() == elfcpp::STT_TLS) + symval.set_is_tls_symbol(); + else if (gsym->type() == elfcpp::STT_GNU_IFUNC) + symval.set_is_ifunc_symbol(); + psymval = &symval; + + is_defined_in_discarded_section = + (gsym->is_defined_in_discarded_section() + && gsym->is_undefined()); + shndx = 0; + } + + Symbol_value<32> symval2; + if (is_defined_in_discarded_section) + { + if (comdat_behavior == CB_UNDETERMINED) + { + std::string name = arm_object->section_name(relinfo->data_shndx); + comdat_behavior = default_comdat_behavior.get(name.c_str()); + } + if (comdat_behavior == CB_PRETEND) + { + // FIXME: This case does not work for global symbols. + // We have no place to store the original section index. + // Fortunately this does not matter for comdat sections, + // only for sections explicitly discarded by a linker + // script. + bool found; + typename elfcpp::Elf_types<32>::Elf_Addr value = + arm_object->map_to_kept_section(shndx, &found); + if (found) + symval2.set_output_value(value + psymval->input_value()); + else + symval2.set_output_value(0); + } + else + { + if (comdat_behavior == CB_WARNING) + gold_warning_at_location(relinfo, i, offset, + _("relocation refers to discarded " + "section")); + symval2.set_output_value(0); + } + symval2.set_no_output_symtab_entry(); + psymval = &symval2; + } + + // If symbol is a section symbol, we don't know the actual type of + // destination. Give up. + if (psymval->is_section_symbol()) + continue; + + this->scan_reloc_for_stub(relinfo, r_type, sym, r_sym, psymval, + addend, view_address + offset); + } +} + +// Scan an input section for stub generation. + +template +void +Target_arm::scan_section_for_stubs( + const Relocate_info<32, big_endian>* relinfo, + unsigned int sh_type, + const unsigned char* prelocs, + size_t reloc_count, + Output_section* output_section, + bool needs_special_offset_handling, + const unsigned char* view, + Arm_address view_address, + section_size_type view_size) +{ + if (sh_type == elfcpp::SHT_REL) + this->scan_reloc_section_for_stubs( + relinfo, + prelocs, + reloc_count, + output_section, + needs_special_offset_handling, + view, + view_address, + view_size); + else if (sh_type == elfcpp::SHT_RELA) + // We do not support RELA type relocations yet. This is provided for + // completeness. + this->scan_reloc_section_for_stubs( + relinfo, + prelocs, + reloc_count, + output_section, + needs_special_offset_handling, + view, + view_address, + view_size); + else + gold_unreachable(); +} + +// Group input sections for stub generation. +// +// We group input sections in an output section so that the total size, +// including any padding space due to alignment is smaller than GROUP_SIZE +// unless the only input section in group is bigger than GROUP_SIZE already. +// Then an ARM stub table is created to follow the last input section +// in group. For each group an ARM stub table is created an is placed +// after the last group. If STUB_ALWAYS_AFTER_BRANCH is false, we further +// extend the group after the stub table. + +template +void +Target_arm::group_sections( + Layout* layout, + section_size_type group_size, + bool stubs_always_after_branch, + const Task* task) +{ + // Group input sections and insert stub table + Layout::Section_list section_list; + layout->get_executable_sections(§ion_list); + for (Layout::Section_list::const_iterator p = section_list.begin(); + p != section_list.end(); + ++p) + { + Arm_output_section* output_section = + Arm_output_section::as_arm_output_section(*p); + output_section->group_sections(group_size, stubs_always_after_branch, + this, task); + } +} + +// Relaxation hook. This is where we do stub generation. + +template +bool +Target_arm::do_relax( + int pass, + const Input_objects* input_objects, + Symbol_table* symtab, + Layout* layout, + const Task* task) +{ + // No need to generate stubs if this is a relocatable link. + gold_assert(!parameters->options().relocatable()); + + // If this is the first pass, we need to group input sections into + // stub groups. + bool done_exidx_fixup = false; + typedef typename Stub_table_list::iterator Stub_table_iterator; + if (pass == 1) + { + // Determine the stub group size. The group size is the absolute + // value of the parameter --stub-group-size. If --stub-group-size + // is passed a negative value, we restrict stubs to be always after + // the stubbed branches. + int32_t stub_group_size_param = + parameters->options().stub_group_size(); + bool stubs_always_after_branch = stub_group_size_param < 0; + section_size_type stub_group_size = abs(stub_group_size_param); + + if (stub_group_size == 1) + { + // Default value. + // Thumb branch range is +-4MB has to be used as the default + // maximum size (a given section can contain both ARM and Thumb + // code, so the worst case has to be taken into account). If we are + // fixing cortex-a8 errata, the branch range has to be even smaller, + // since wide conditional branch has a range of +-1MB only. + // + // This value is 48K less than that, which allows for 4096 + // 12-byte stubs. If we exceed that, then we will fail to link. + // The user will have to relink with an explicit group size + // option. + stub_group_size = 4145152; + } + + // The Cortex-A8 erratum fix depends on stubs not being in the same 4K + // page as the first half of a 32-bit branch straddling two 4K pages. + // This is a crude way of enforcing that. In addition, long conditional + // branches of THUMB-2 have a range of +-1M. If we are fixing cortex-A8 + // erratum, limit the group size to (1M - 12k) to avoid unreachable + // cortex-A8 stubs from long conditional branches. + if (this->fix_cortex_a8_) + { + stubs_always_after_branch = true; + const section_size_type cortex_a8_group_size = 1024 * (1024 - 12); + stub_group_size = std::max(stub_group_size, cortex_a8_group_size); + } + + group_sections(layout, stub_group_size, stubs_always_after_branch, task); + + // Also fix .ARM.exidx section coverage. + Arm_output_section* exidx_output_section = NULL; + for (Layout::Section_list::const_iterator p = + layout->section_list().begin(); + p != layout->section_list().end(); + ++p) + if ((*p)->type() == elfcpp::SHT_ARM_EXIDX) + { + if (exidx_output_section == NULL) + exidx_output_section = + Arm_output_section::as_arm_output_section(*p); + else + // We cannot handle this now. + gold_error(_("multiple SHT_ARM_EXIDX sections %s and %s in a " + "non-relocatable link"), + exidx_output_section->name(), + (*p)->name()); + } + + if (exidx_output_section != NULL) + { + this->fix_exidx_coverage(layout, input_objects, exidx_output_section, + symtab, task); + done_exidx_fixup = true; + } + } + else + { + // If this is not the first pass, addresses and file offsets have + // been reset at this point, set them here. + for (Stub_table_iterator sp = this->stub_tables_.begin(); + sp != this->stub_tables_.end(); + ++sp) + { + Arm_input_section* owner = (*sp)->owner(); + off_t off = align_address(owner->original_size(), + (*sp)->addralign()); + (*sp)->set_address_and_file_offset(owner->address() + off, + owner->offset() + off); + } + } + + // The Cortex-A8 stubs are sensitive to layout of code sections. At the + // beginning of each relaxation pass, just blow away all the stubs. + // Alternatively, we could selectively remove only the stubs and reloc + // information for code sections that have moved since the last pass. + // That would require more book-keeping. + if (this->fix_cortex_a8_) + { + // Clear all Cortex-A8 reloc information. + for (typename Cortex_a8_relocs_info::const_iterator p = + this->cortex_a8_relocs_info_.begin(); + p != this->cortex_a8_relocs_info_.end(); + ++p) + delete p->second; + this->cortex_a8_relocs_info_.clear(); + + // Remove all Cortex-A8 stubs. + for (Stub_table_iterator sp = this->stub_tables_.begin(); + sp != this->stub_tables_.end(); + ++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(); + ++op) + { + Arm_relobj* arm_relobj = + Arm_relobj::as_arm_relobj(*op); + // Lock the object so we can read from it. This is only called + // single-threaded from Layout::finalize, so it is OK to lock. + Task_lock_obj tl(task, arm_relobj); + arm_relobj->scan_sections_for_stubs(this, symtab, layout); + } + + // Check all stub tables to see if any of them have their data sizes + // or addresses alignments changed. These are the only things that + // matter. + bool any_stub_table_changed = false; + Unordered_set sections_needing_adjustment; + for (Stub_table_iterator sp = this->stub_tables_.begin(); + (sp != this->stub_tables_.end()) && !any_stub_table_changed; + ++sp) + { + if ((*sp)->update_data_size_and_addralign()) + { + // Update data size of stub table owner. + Arm_input_section* owner = (*sp)->owner(); + uint64_t address = owner->address(); + off_t offset = owner->offset(); + owner->reset_address_and_file_offset(); + owner->set_address_and_file_offset(address, offset); + + sections_needing_adjustment.insert(owner->output_section()); + any_stub_table_changed = true; + } + } + + // Output_section_data::output_section() returns a const pointer but we + // need to update output sections, so we record all output sections needing + // update above and scan the sections here to find out what sections need + // to be updated. + for (Layout::Section_list::const_iterator p = layout->section_list().begin(); + p != layout->section_list().end(); + ++p) + { + if (sections_needing_adjustment.find(*p) + != sections_needing_adjustment.end()) + (*p)->set_section_offsets_need_adjustment(); + } + + // Stop relaxation if no EXIDX fix-up and no stub table change. + bool continue_relaxation = done_exidx_fixup || any_stub_table_changed; + + // Finalize the stubs in the last relaxation pass. + if (!continue_relaxation) + { + for (Stub_table_iterator sp = this->stub_tables_.begin(); + (sp != this->stub_tables_.end()) && !any_stub_table_changed; + ++sp) + (*sp)->finalize_stubs(); + + // Update output local symbol counts of objects if necessary. + for (Input_objects::Relobj_iterator op = input_objects->relobj_begin(); + op != input_objects->relobj_end(); + ++op) + { + Arm_relobj* arm_relobj = + Arm_relobj::as_arm_relobj(*op); + + // Update output local symbol counts. We need to discard local + // symbols defined in parts of input sections that are discarded by + // relaxation. + if (arm_relobj->output_local_symbol_count_needs_update()) + { + // We need to lock the object's file to update it. + Task_lock_obj tl(task, arm_relobj); + arm_relobj->update_output_local_symbol_count(); + } + } + } + + return continue_relaxation; +} + +// Relocate a stub. + +template +void +Target_arm::relocate_stub( + Stub* stub, + const Relocate_info<32, big_endian>* relinfo, + Output_section* output_section, + unsigned char* view, + Arm_address address, + section_size_type view_size) +{ + Relocate relocate; + const Stub_template* stub_template = stub->stub_template(); + for (size_t i = 0; i < stub_template->reloc_count(); i++) + { + size_t reloc_insn_index = stub_template->reloc_insn_index(i); + const Insn_template* insn = &stub_template->insns()[reloc_insn_index]; + + unsigned int r_type = insn->r_type(); + section_size_type reloc_offset = stub_template->reloc_offset(i); + section_size_type reloc_size = insn->size(); + gold_assert(reloc_offset + reloc_size <= view_size); + + // This is the address of the stub destination. + Arm_address target = stub->reloc_target(i) + insn->reloc_addend(); + Symbol_value<32> symval; + symval.set_output_value(target); + + // Synthesize a fake reloc just in case. We don't have a symbol so + // we use 0. + unsigned char reloc_buffer[elfcpp::Elf_sizes<32>::rel_size]; + memset(reloc_buffer, 0, sizeof(reloc_buffer)); + elfcpp::Rel_write<32, big_endian> reloc_write(reloc_buffer); + reloc_write.put_r_offset(reloc_offset); + reloc_write.put_r_info(elfcpp::elf_r_info<32>(0, r_type)); + elfcpp::Rel<32, big_endian> rel(reloc_buffer); + + relocate.relocate(relinfo, this, output_section, + this->fake_relnum_for_stubs, rel, r_type, + NULL, &symval, view + reloc_offset, + address + reloc_offset, reloc_size); + } +} + +// Determine whether an object attribute tag takes an integer, a +// string or both. + +template +int +Target_arm::do_attribute_arg_type(int tag) const +{ + if (tag == Object_attribute::Tag_compatibility) + return (Object_attribute::ATTR_TYPE_FLAG_INT_VAL + | Object_attribute::ATTR_TYPE_FLAG_STR_VAL); + else if (tag == elfcpp::Tag_nodefaults) + return (Object_attribute::ATTR_TYPE_FLAG_INT_VAL + | Object_attribute::ATTR_TYPE_FLAG_NO_DEFAULT); + else if (tag == elfcpp::Tag_CPU_raw_name || tag == elfcpp::Tag_CPU_name) + return Object_attribute::ATTR_TYPE_FLAG_STR_VAL; + else if (tag < 32) + return Object_attribute::ATTR_TYPE_FLAG_INT_VAL; + else + return ((tag & 1) != 0 + ? Object_attribute::ATTR_TYPE_FLAG_STR_VAL + : Object_attribute::ATTR_TYPE_FLAG_INT_VAL); +} + +// Reorder attributes. +// +// The ABI defines that Tag_conformance should be emitted first, and that +// Tag_nodefaults should be second (if either is defined). This sets those +// two positions, and bumps up the position of all the remaining tags to +// compensate. + +template +int +Target_arm::do_attributes_order(int num) const +{ + // Reorder the known object attributes in output. We want to move + // Tag_conformance to position 4 and Tag_conformance to position 5 + // and shift everything between 4 .. Tag_conformance - 1 to make room. + if (num == 4) + return elfcpp::Tag_conformance; + if (num == 5) + return elfcpp::Tag_nodefaults; + if ((num - 2) < elfcpp::Tag_nodefaults) + return num - 2; + if ((num - 1) < elfcpp::Tag_conformance) + return num - 1; + return num; +} + +// Scan a span of THUMB code for Cortex-A8 erratum. + +template +void +Target_arm::scan_span_for_cortex_a8_erratum( + Arm_relobj* arm_relobj, + unsigned int shndx, + section_size_type span_start, + section_size_type span_end, + const unsigned char* view, + Arm_address address) +{ + // Scan for 32-bit Thumb-2 branches which span two 4K regions, where: + // + // The opcode is BLX.W, BL.W, B.W, Bcc.W + // The branch target is in the same 4KB region as the + // first half of the branch. + // The instruction before the branch is a 32-bit + // length non-branch instruction. + section_size_type i = span_start; + bool last_was_32bit = false; + bool last_was_branch = false; + while (i < span_end) + { + typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype; + const Valtype* wv = reinterpret_cast(view + i); + uint32_t insn = elfcpp::Swap<16, big_endian>::readval(wv); + bool is_blx = false, is_b = false; + bool is_bl = false, is_bcc = false; + + bool insn_32bit = (insn & 0xe000) == 0xe000 && (insn & 0x1800) != 0x0000; + if (insn_32bit) + { + // Load the rest of the insn (in manual-friendly order). + insn = (insn << 16) | elfcpp::Swap<16, big_endian>::readval(wv + 1); + + // Encoding T4: B.W. + is_b = (insn & 0xf800d000U) == 0xf0009000U; + // Encoding T1: BL.W. + is_bl = (insn & 0xf800d000U) == 0xf000d000U; + // Encoding T2: BLX.W. + is_blx = (insn & 0xf800d000U) == 0xf000c000U; + // Encoding T3: B.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. + if (is_32bit_branch + && ((address + i) & 0xfffU) == 0xffeU + && last_was_32bit + && !last_was_branch) + { + // Check to see if there is a relocation stub for this branch. + bool force_target_arm = false; + bool force_target_thumb = false; + const Cortex_a8_reloc* cortex_a8_reloc = NULL; + Cortex_a8_relocs_info::const_iterator p = + this->cortex_a8_relocs_info_.find(address + i); + + if (p != this->cortex_a8_relocs_info_.end()) + { + cortex_a8_reloc = p->second; + bool target_is_thumb = (cortex_a8_reloc->destination() & 1) != 0; + + if (cortex_a8_reloc->r_type() == elfcpp::R_ARM_THM_CALL + && !target_is_thumb) + force_target_arm = true; + else if (cortex_a8_reloc->r_type() == elfcpp::R_ARM_THM_CALL + && target_is_thumb) + force_target_thumb = true; + } + + off_t offset; + Stub_type stub_type = arm_stub_none; + + // Check if we have an offending branch instruction. + uint16_t upper_insn = (insn >> 16) & 0xffffU; + uint16_t lower_insn = insn & 0xffffU; + typedef class Arm_relocate_functions RelocFuncs; + + if (cortex_a8_reloc != NULL + && cortex_a8_reloc->reloc_stub() != NULL) + // We've already made a stub for this instruction, e.g. + // it's a long branch or a Thumb->ARM stub. Assume that + // stub will suffice to work around the A8 erratum (see + // setting of always_after_branch above). + ; + else if (is_bcc) + { + offset = RelocFuncs::thumb32_cond_branch_offset(upper_insn, + lower_insn); + stub_type = arm_stub_a8_veneer_b_cond; + } + else if (is_b || is_bl || is_blx) + { + offset = RelocFuncs::thumb32_branch_offset(upper_insn, + lower_insn); + if (is_blx) + offset &= ~3; + + stub_type = (is_blx + ? arm_stub_a8_veneer_blx + : (is_bl + ? arm_stub_a8_veneer_bl + : arm_stub_a8_veneer_b)); + } + + if (stub_type != arm_stub_none) + { + Arm_address pc_for_insn = address + i + 4; + + // The original instruction is a BL, but the target is + // an ARM instruction. If we were not making a stub, + // the BL would have been converted to a BLX. Use the + // BLX stub instead in that case. + if (this->may_use_v5t_interworking() && force_target_arm + && stub_type == arm_stub_a8_veneer_bl) + { + stub_type = arm_stub_a8_veneer_blx; + is_blx = true; + is_bl = false; + } + // Conversely, if the original instruction was + // BLX but the target is Thumb mode, use the BL stub. + else if (force_target_thumb + && stub_type == arm_stub_a8_veneer_blx) + { + stub_type = arm_stub_a8_veneer_bl; + is_blx = false; + is_bl = true; + } + + if (is_blx) + pc_for_insn &= ~3; + + // 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); + + 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)) + { + Cortex_a8_stub* stub = + this->stub_factory_.make_cortex_a8_stub(stub_type, + arm_relobj, shndx, + address + i, + target, insn); + Stub_table* stub_table = + 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; + last_was_branch = is_32bit_branch; + } +} + +// Apply the Cortex-A8 workaround. + +template +void +Target_arm::apply_cortex_a8_workaround( + const Cortex_a8_stub* stub, + Arm_address stub_address, + unsigned char* insn_view, + Arm_address insn_address) +{ + typedef typename elfcpp::Swap<16, big_endian>::Valtype Valtype; + Valtype* wv = reinterpret_cast(insn_view); + Valtype upper_insn = elfcpp::Swap<16, big_endian>::readval(wv); + Valtype lower_insn = elfcpp::Swap<16, big_endian>::readval(wv + 1); + off_t branch_offset = stub_address - (insn_address + 4); + + typedef class Arm_relocate_functions RelocFuncs; + switch (stub->stub_template()->type()) + { + case arm_stub_a8_veneer_b_cond: + // For a conditional branch, we re-write it to be an unconditional + // branch to the stub. We use the THUMB-2 encoding here. + upper_insn = 0xf000U; + lower_insn = 0xb800U; + // Fall through + case arm_stub_a8_veneer_b: + case arm_stub_a8_veneer_bl: + case arm_stub_a8_veneer_blx: + if ((lower_insn & 0x5000U) == 0x4000U) + // For a BLX instruction, make sure that the relocation is + // rounded up to a word boundary. This follows the semantics of + // the instruction which specifies that bit 1 of the target + // address will come from bit 1 of the base address. + branch_offset = (branch_offset + 2) & ~3; + + // Put BRANCH_OFFSET back into the insn. + gold_assert(!Bits<25>::has_overflow32(branch_offset)); + upper_insn = RelocFuncs::thumb32_branch_upper(upper_insn, branch_offset); + lower_insn = RelocFuncs::thumb32_branch_lower(lower_insn, branch_offset); + break; + + default: + gold_unreachable(); + } + + // Put the relocated value back in the object file: + elfcpp::Swap<16, big_endian>::writeval(wv, upper_insn); + 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 +class Target_selector_arm : public Target_selector +{ + public: + Target_selector_arm() + : Target_selector(elfcpp::EM_ARM, 32, big_endian, + (big_endian ? "elf32-bigarm" : "elf32-littlearm"), + (big_endian ? "armelfb" : "armelf")) + { } + + Target* + do_instantiate_target() + { return new Target_arm(); } +}; + +// Fix .ARM.exidx section coverage. + +template +void +Target_arm::fix_exidx_coverage( + Layout* layout, + const Input_objects* input_objects, + Arm_output_section* exidx_section, + Symbol_table* symtab, + const Task* task) +{ + // We need to look at all the input sections in output in ascending + // order of of output address. We do that by building a sorted list + // of output sections by addresses. Then we looks at the output sections + // in order. The input sections in an output section are already sorted + // by addresses within the output section. + + typedef std::set + Sorted_output_section_list; + Sorted_output_section_list sorted_output_sections; + + // Find out all the output sections of input sections pointed by + // EXIDX input sections. + for (Input_objects::Relobj_iterator p = input_objects->relobj_begin(); + p != input_objects->relobj_end(); + ++p) + { + Arm_relobj* arm_relobj = + Arm_relobj::as_arm_relobj(*p); + std::vector shndx_list; + arm_relobj->get_exidx_shndx_list(&shndx_list); + for (size_t i = 0; i < shndx_list.size(); ++i) + { + const Arm_exidx_input_section* exidx_input_section = + arm_relobj->exidx_input_section_by_shndx(shndx_list[i]); + gold_assert(exidx_input_section != NULL); + if (!exidx_input_section->has_errors()) + { + unsigned int text_shndx = exidx_input_section->link(); + Output_section* os = arm_relobj->output_section(text_shndx); + if (os != NULL && (os->flags() & elfcpp::SHF_ALLOC) != 0) + sorted_output_sections.insert(os); + } + } + } + + // Go over the output sections in ascending order of output addresses. + typedef typename Arm_output_section::Text_section_list + Text_section_list; + Text_section_list sorted_text_sections; + for (typename Sorted_output_section_list::iterator p = + sorted_output_sections.begin(); + p != sorted_output_sections.end(); + ++p) + { + Arm_output_section* arm_output_section = + Arm_output_section::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); +} + +template +void +Target_arm::do_define_standard_symbols( + Symbol_table* symtab, + Layout* layout) +{ + // Handle the .ARM.exidx section. + Output_section* exidx_section = layout->find_output_section(".ARM.exidx"); + + if (exidx_section != NULL) + { + // Create __exidx_start and __exidx_end symbols. + symtab->define_in_output_data("__exidx_start", + NULL, // version + Symbol_table::PREDEFINED, + exidx_section, + 0, // value + 0, // symsize + elfcpp::STT_NOTYPE, + elfcpp::STB_GLOBAL, + elfcpp::STV_HIDDEN, + 0, // nonvis + false, // offset_is_from_end + true); // only_if_ref + + symtab->define_in_output_data("__exidx_end", + NULL, // version + Symbol_table::PREDEFINED, + exidx_section, + 0, // value + 0, // symsize + elfcpp::STT_NOTYPE, + elfcpp::STB_GLOBAL, + elfcpp::STV_HIDDEN, + 0, // nonvis + true, // offset_is_from_end + true); // only_if_ref + } + else + { + // 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); + symtab->define_as_constant("__exidx_end", NULL, + Symbol_table::PREDEFINED, + 0, 0, elfcpp::STT_OBJECT, + elfcpp::STB_GLOBAL, elfcpp::STV_HIDDEN, 0, + true, false); + } +} + +// NaCl variant. It uses different PLT contents. + +template +class Output_data_plt_arm_nacl; + +template +class Target_arm_nacl : public Target_arm +{ + public: + Target_arm_nacl() + : Target_arm(&arm_nacl_info) + { } + + protected: + virtual Output_data_plt_arm* + do_make_data_plt(Layout* layout, Output_data_space* got_plt) + { return new Output_data_plt_arm_nacl(layout, got_plt); } + + private: + static const Target::Target_info arm_nacl_info; +}; + +template +const Target::Target_info Target_arm_nacl::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 + "_start" // entry_symbol_name +}; + +template +class Output_data_plt_arm_nacl : public Output_data_plt_arm +{ + public: + Output_data_plt_arm_nacl(Layout* layout, Output_data_space* got_plt) + : Output_data_plt_arm(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 +const uint32_t Output_data_plt_arm_nacl::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: + 0xe3ccc103, // bic ip, ip, #0xc0000000 + 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: + 0xe3ccc103, // bic ip, ip, #0xc0000000 + 0xe59cc000, // ldr ip, [ip] + 0xe3ccc13f, // bic ip, ip, #0xc000000f + 0xe12fff1c, // bx ip +}; + +template +void +Output_data_plt_arm_nacl::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 +const uint32_t Output_data_plt_arm_nacl::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 +void +Output_data_plt_arm_nacl::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 +class Target_selector_arm_nacl + : public Target_selector_nacl, + Target_arm_nacl > +{ + public: + Target_selector_arm_nacl() + : Target_selector_nacl, + Target_arm_nacl >( + "arm", + big_endian ? "elf32-bigarm-nacl" : "elf32-littlearm-nacl", + big_endian ? "armelfb_nacl" : "armelf_nacl") + { } +}; + +Target_selector_arm_nacl target_selector_arm; +Target_selector_arm_nacl target_selector_armbe; + +} // End anonymous namespace. diff --git a/binutils-2.25/gold/attributes.cc b/binutils-2.25/gold/attributes.cc new file mode 100644 index 00000000..45ab5a0c --- /dev/null +++ b/binutils-2.25/gold/attributes.cc @@ -0,0 +1,458 @@ +// attributes.cc -- object attributes for gold + +// Copyright 2009 Free Software Foundation, Inc. +// Written by Doug Kwan . +// This file contains code adapted from BFD. + +// 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 + +#include "attributes.h" +#include "elfcpp.h" +#include "target.h" +#include "parameters.h" +#include "int_encoding.h" + +namespace gold +{ + +// Object_attribute methods. + +// Return size of attribute encode in ULEB128. + +size_t +Object_attribute::size(int tag) const +{ + // Attributes with default values are not written out. + if (this->is_default_attribute()) + return 0; + + size_t size = get_length_as_unsigned_LEB_128(tag); + if (Object_attribute::attribute_type_has_int_value(this->type_)) + size += get_length_as_unsigned_LEB_128(this->int_value_); + if (Object_attribute::attribute_type_has_string_value(this->type_)) + size += this->string_value_.size() + 1; + return size; +} + +// Whether this has the default value (0/""). + +bool +Object_attribute::is_default_attribute() const +{ + if (Object_attribute::attribute_type_has_int_value(this->type_) + && this->int_value_ != 0) + return false; + if (Object_attribute::attribute_type_has_string_value(this->type_) + && !this->string_value_.empty()) + return false; + if (Object_attribute::attribute_type_has_no_default(this->type_)) + return false; + + return true; +} + +// Whether this matches another Object_attribute OA in merging. +// Two Object_attributes match if they have the same values. + +bool +Object_attribute::matches(const Object_attribute& oa) const +{ + return ((this->int_value_ != oa.int_value_) + && (this->string_value_ == oa.string_value_)); +} + +// Write this with TAG to a BUFFER. + +void +Object_attribute::write( + int tag, + std::vector* buffer) const +{ + // No need to write default attributes. + if (this->is_default_attribute()) + return; + + // Write tag. + write_unsigned_LEB_128(buffer, convert_types(tag)); + + // Write integer value. + if (Object_attribute::attribute_type_has_int_value(this->type_)) + write_unsigned_LEB_128(buffer, + convert_types(this->int_value_)); + + // Write string value. + if (Object_attribute::attribute_type_has_string_value(this->type_)) + { + const unsigned char* start = + reinterpret_cast(this->string_value_.c_str()); + const unsigned char* end = start + this->string_value_.size() + 1; + buffer->insert(buffer->end(), start, end); + } +} + +// Vendor_object_attributes methods. + +// Copying constructor. + +Vendor_object_attributes::Vendor_object_attributes( + const Vendor_object_attributes& voa) +{ + this->vendor_ = voa.vendor_; + + for (int i = 0; i < NUM_KNOWN_ATTRIBUTES; ++i) + this->known_attributes_[i] = voa.known_attributes_[i]; + + // We do not handle attribute deletion. So this must be empty. + gold_assert(this->other_attributes_.empty()); + + for (Other_attributes::const_iterator p = voa.other_attributes_.begin(); + p != voa.other_attributes_.end(); + ++p) + this->other_attributes_[p->first] = new Object_attribute(*(p->second)); +} + +// Size of this in number of bytes. + +size_t +Vendor_object_attributes::size() const +{ + if (this->name() == NULL) + return 0; + + size_t data_size = 0; + for (int i = 4; i < NUM_KNOWN_ATTRIBUTES; ++i) + data_size += this->known_attributes_[i].size(i); + + for (Other_attributes::const_iterator p = this->other_attributes_.begin(); + p != this->other_attributes_.end(); + ++p) + data_size += p->second->size(p->first); + + // NUL 0x1 + return ((data_size != 0 + || this->vendor_ == Object_attribute::OBJ_ATTR_PROC) + ? data_size + strlen(this->name()) + 2 + 2 * 4 + : 0); +} + +// Return a new attribute associated with TAG. + +Object_attribute* +Vendor_object_attributes::new_attribute(int tag) +{ + int type = Object_attribute::arg_type(this->vendor_, tag); + + if (tag < NUM_KNOWN_ATTRIBUTES) + { + this->known_attributes_[tag].set_type(type); + return &this->known_attributes_[tag]; + } + else + { + Object_attribute* attr = new Object_attribute(); + + // This should be the first time we insert this. + std::pair ins = + this->other_attributes_.insert(std::make_pair(tag, attr)); + gold_assert(ins.second); + + attr->set_type(type); + return attr; + } +} + +// Return an attribute associated with TAG. + +Object_attribute* +Vendor_object_attributes::get_attribute(int tag) +{ + if (tag < NUM_KNOWN_ATTRIBUTES) + return &this->known_attributes_[tag]; + else + { + Other_attributes::iterator p = + this->other_attributes_.find(tag); + return p != this->other_attributes_.end() ? p->second : NULL; + } +} + +const Object_attribute* +Vendor_object_attributes::get_attribute(int tag) const +{ + if (tag < NUM_KNOWN_ATTRIBUTES) + return &this->known_attributes_[tag]; + else + { + Other_attributes::const_iterator p = + this->other_attributes_.find(tag); + return p != this->other_attributes_.end() ? p->second : NULL; + } +} + +// Write attributes to BUFFER. + +void +Vendor_object_attributes::write(std::vector* buffer) const +{ + // Write subsection size. + size_t voa_size = this->size(); + uint32_t voa_size_as_u32 = convert_types(voa_size); + insert_into_vector<32>(buffer, voa_size_as_u32); + + // Write vendor name. + const unsigned char* vendor_start = + reinterpret_cast(this->name()); + size_t vendor_length = strlen(this->name()) + 1; + const unsigned char* vendor_end = vendor_start + vendor_length; + buffer->insert(buffer->end(), vendor_start, vendor_end); + + // Write file tag. + buffer->push_back(Object_attribute::Tag_File); + + // Write attributes size. + uint32_t attributes_size_as_u32 = + convert_types(voa_size - 4 - vendor_length); + insert_into_vector<32>(buffer, attributes_size_as_u32); + + // Write known attributes, skipping any defaults. + for (int i = 4; i < NUM_KNOWN_ATTRIBUTES; ++i) + { + // A target may write known attributes in a special order. + // Call target hook to remap tags. Attributes_order is the identity + // function if no re-ordering is required. + int tag = parameters->target().attributes_order(i); + this->known_attributes_[tag].write(tag, buffer); + } + + // Write other attributes. + for (Other_attributes::const_iterator q = this->other_attributes_.begin(); + q != this->other_attributes_.end(); + ++q) + q->second->write(q->first, buffer); +} + +// Attributes_section_data methods. + +// Compute encoded size of this. + +size_t +Attributes_section_data::size() const +{ + size_t data_size = 0; + for(int vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; ++vendor) + data_size += this->vendor_object_attributes_[vendor]->size(); + + // 'A' + return data_size != 0 ? data_size + 1 : 0; +} + +// Construct an Attributes_section_data object by parsing section contents +// specified by VIEW and SIZE. + +Attributes_section_data::Attributes_section_data( + const unsigned char* view, + section_size_type size) +{ + for (int vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; ++vendor) + this->vendor_object_attributes_[vendor] = + new Vendor_object_attributes(vendor); + + const unsigned char* p = view; + p = view; + if (size > 0 && p != NULL && *(p++) == 'A') + { + size--; + while (size > 0) + { + // Size of vendor attributes section. + section_size_type section_size = + convert_to_section_size_type(read_from_pointer<32>(&p)); + + if (section_size > size) + section_size = size; + size -= section_size; + + const char* section_name = reinterpret_cast(p); + section_size_type section_name_size = strlen(section_name) + 1; + section_size -= section_name_size + 4; + + int vendor; + const char* std_section = parameters->target().attributes_vendor(); + if (std_section != NULL && strcmp(section_name, std_section) == 0) + vendor = Object_attribute::OBJ_ATTR_PROC; + else if (strcmp(section_name, "gnu") == 0) + vendor = Object_attribute::OBJ_ATTR_GNU; + else + { + // Other vendor section. Ignore it. + p += section_name_size + section_size; + continue; + } + p += section_name_size; + + while (section_size > 0) + { + const unsigned char* subsection_start = p; + + // Read vendor subsection index and size. + size_t uleb128_len; + uint64_t val = read_unsigned_LEB_128(p, &uleb128_len); + p += uleb128_len; + + int tag = convert_types(val); + section_size_type subsection_size = + convert_to_section_size_type(read_from_pointer<32>(&p)); + section_size -= subsection_size; + subsection_size -= (p - subsection_start); + + const unsigned char* end = p + subsection_size; + switch (tag) + { + case Object_attribute::Tag_File: + while (p < end) + { + val = read_unsigned_LEB_128(p, &uleb128_len); + p += uleb128_len; + tag = convert_types(val); + Vendor_object_attributes* pvoa = + this->vendor_object_attributes_[vendor]; + Object_attribute* attr = pvoa->new_attribute(tag); + const char* string_arg; + unsigned int int_arg; + + int type = Object_attribute::arg_type(vendor, tag); + switch (type + & (Object_attribute::ATTR_TYPE_FLAG_INT_VAL + | Object_attribute::ATTR_TYPE_FLAG_STR_VAL)) + { + case (Object_attribute::ATTR_TYPE_FLAG_INT_VAL + | Object_attribute::ATTR_TYPE_FLAG_STR_VAL): + val = read_unsigned_LEB_128(p, &uleb128_len); + p += uleb128_len; + int_arg = convert_types(val); + string_arg = reinterpret_cast(p); + attr->set_int_value(int_arg); + p += strlen(string_arg) + 1; + break; + case Object_attribute::ATTR_TYPE_FLAG_STR_VAL: + string_arg = reinterpret_cast(p); + attr->set_string_value(string_arg); + p += strlen(string_arg) + 1; + break; + case Object_attribute::ATTR_TYPE_FLAG_INT_VAL: + val = read_unsigned_LEB_128(p, &uleb128_len); + p += uleb128_len; + int_arg = convert_types(val); + attr->set_int_value(int_arg); + break; + default: + gold_unreachable(); + } + } + break; + case Object_attribute::Tag_Section: + case Object_attribute::Tag_Symbol: + // Don't have anywhere convenient to attach these. + // Fall through for now. + default: + // Ignore things we don't know about. + p += subsection_size; + subsection_size = 0; + break; + } + } + } + } +} + +// Merge target-independent attributes from another Attribute_section_data +// ASD from an object called NAME into this. + +void +Attributes_section_data::merge( + const char* name, + const Attributes_section_data* pasd) +{ + // The only common attribute is currently Tag_compatibility, + // accepted in both processor and "gnu" sections. + for (int vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; ++vendor) + { + // Handle Tag_compatibility. The tags are only compatible if the flags + // are identical and, if the flags are '1', the strings are identical. + // If the flags are non-zero, then we can only use the string "gnu". + const Object_attribute* in_attr = + &pasd->known_attributes(vendor)[Object_attribute::Tag_compatibility]; + Object_attribute* out_attr = + &this->known_attributes(vendor)[Object_attribute::Tag_compatibility]; + + if (in_attr->int_value() > 0 + && in_attr->string_value() != "gnu") + { + gold_error(_("%s: must be processed by '%s' toolchain"), + name, in_attr->string_value().c_str()); + return; + } + + if (in_attr->int_value() != out_attr->int_value() + || in_attr->string_value() != out_attr->string_value()) + { + gold_error(_("%s: object tag '%d, %s' is " + "incompatible with tag '%d, %s'"), + name, in_attr->int_value(), + in_attr->string_value().c_str(), + out_attr->int_value(), + out_attr->string_value().c_str()); + } + } +} + +// Write to a buffer. + +void +Attributes_section_data::write(std::vector* buffer) const +{ + buffer->push_back('A'); + for (int vendor = OBJ_ATTR_FIRST; vendor <= OBJ_ATTR_LAST; ++vendor) + if (this->vendor_object_attributes_[vendor]->size() != 0) + this->vendor_object_attributes_[vendor]->write(buffer); +} + +// Methods for Output_attributes_section_data. + +// Write attributes section data to file OF. + +void +Output_attributes_section_data::do_write(Output_file* of) +{ + off_t offset = this->offset(); + const section_size_type oview_size = + convert_to_section_size_type(this->data_size()); + unsigned char* const oview = of->get_output_view(offset, oview_size); + + std::vector buffer; + this->attributes_section_data_.write(&buffer); + gold_assert(convert_to_section_size_type(buffer.size()) == oview_size); + memcpy(oview, &buffer.front(), buffer.size()); + of->write_output_view(this->offset(), oview_size, oview); +} + +} // End namespace gold. diff --git a/binutils-2.25/gold/attributes.h b/binutils-2.25/gold/attributes.h new file mode 100644 index 00000000..26fe1580 --- /dev/null +++ b/binutils-2.25/gold/attributes.h @@ -0,0 +1,406 @@ +// attributes.h -- object attributes for gold -*- C++ -*- + +// Copyright 2009, 2010 Free Software Foundation, Inc. +// Written by Doug Kwan . +// This file contains code adapted from BFD. + +// 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. + +// Handle object attributes. + +#ifndef GOLD_ATTRIBUTES_H +#define GOLD_ATTRIBUTES_H + +#include + +#include "parameters.h" +#include "target.h" +#include "output.h" +#include "reduced_debug_output.h" + +namespace gold +{ + +// Object attribute values. The attribute tag is not stored in this object. + +class Object_attribute +{ + public: + // The value of an object attribute. The type indicates whether the + // attribute holds and integer, a string, or both. It can also indicate that + // there can be no default (i.e. all values must be written to file, even + // zero). + enum + { + ATTR_TYPE_FLAG_INT_VAL = (1 << 0), + ATTR_TYPE_FLAG_STR_VAL = (1 << 1), + ATTR_TYPE_FLAG_NO_DEFAULT = (1 << 2) + }; + + // Object attributes may either be defined by the processor ABI, index + // OBJ_ATTR_PROC in the *_obj_attributes arrays, or be GNU-specific + // (and possibly also processor-specific), index OBJ_ATTR_GNU. + enum + { + OBJ_ATTR_PROC, + OBJ_ATTR_GNU, + OBJ_ATTR_FIRST = OBJ_ATTR_PROC, + OBJ_ATTR_LAST = OBJ_ATTR_GNU + }; + + // The following object attribute tags are taken as generic, for all + // targets and for "gnu" where there is no target standard. + enum + { + Tag_NULL = 0, + Tag_File = 1, + Tag_Section = 2, + Tag_Symbol = 3, + Tag_compatibility = 32 + }; + + Object_attribute() + : type_(0), int_value_(0), string_value_() + { } + + // Copying constructor. We need to implement this to copy the string value. + Object_attribute(const Object_attribute& oa) + : type_(oa.type_), int_value_(oa.int_value_), string_value_(oa.string_value_) + { } + + ~Object_attribute() + { } + + // Assignment operator. We need to implement this to copy the string value. + Object_attribute& + operator=(const Object_attribute& source) + { + this->type_ = source.type_; + this->int_value_ = source.int_value_; + this->string_value_ = source.string_value_; + return *this; + } + + // Return attribute type. + int + type() const + { return this->type_; } + + // Set attribute type. + void + set_type(int type) + { this->type_ = type; } + + // Return integer value. + unsigned int + int_value() const + { return this->int_value_; } + + // Set integer value. + void + set_int_value(unsigned int i) + { this->int_value_ = i; } + + // Return string value. + const std::string& + string_value() const + { return this->string_value_; } + + // Set string value. + void + set_string_value(const std::string& s) + { this->string_value_ = s; } + + void + set_string_value(const char* s) + { this->string_value_ = s; } + + // Whether attribute type has integer value. + static bool + attribute_type_has_int_value(int type) + { return (type & ATTR_TYPE_FLAG_INT_VAL) != 0; } + + // Whether attribute type has string value. + static bool + attribute_type_has_string_value(int type) + { return (type & ATTR_TYPE_FLAG_STR_VAL) != 0; } + + // Whether attribute type has no default value. + static bool + attribute_type_has_no_default(int type) + { return (type & ATTR_TYPE_FLAG_NO_DEFAULT) != 0; } + + // Whether this has default value (0/""). + bool + is_default_attribute() const; + + // Return ULEB128 encoded size of tag and attribute. + size_t + size(int tag) const; + + // Whether this matches another object attribute in merging. + bool + matches(const Object_attribute& oa) const; + + // Write to attribute with tag to BUFFER. + void + write(int tag, std::vector* buffer) const; + + // Determine what arguments an attribute tag takes. + static int + arg_type(int vendor, int tag) + { + switch (vendor) + { + case OBJ_ATTR_PROC: + return parameters->target().attribute_arg_type(tag); + case OBJ_ATTR_GNU: + return Object_attribute::gnu_arg_type(tag); + default: + gold_unreachable(); + } + } + + private: + // Determine whether a GNU object attribute tag takes an integer, a + // string or both. */ + static int + gnu_arg_type(int tag) + { + // Except for Tag_compatibility, for GNU attributes we follow the + // same rule ARM ones > 32 follow: odd-numbered tags take strings + // and even-numbered tags take integers. In addition, tag & 2 is + // nonzero for architecture-independent tags and zero for + // architecture-dependent ones. + if (tag == Object_attribute::Tag_compatibility) + return ATTR_TYPE_FLAG_INT_VAL | ATTR_TYPE_FLAG_STR_VAL; + else + return (tag & 1) != 0 ? ATTR_TYPE_FLAG_STR_VAL : ATTR_TYPE_FLAG_INT_VAL; + } + + // Attribute type. + int type_; + // Integer value. + int int_value_; + // String value. + std::string string_value_; +}; + +// This class contains attributes of a particular vendor. + +class Vendor_object_attributes +{ + public: + // The maximum number of known object attributes for any target. + static const int NUM_KNOWN_ATTRIBUTES = 71; + + Vendor_object_attributes(int vendor) + : vendor_(vendor), other_attributes_() + { } + + // Copying constructor. + Vendor_object_attributes(const Vendor_object_attributes&); + + ~Vendor_object_attributes() + { + for (Other_attributes::iterator p = this->other_attributes_.begin(); + p != this->other_attributes_.end(); + ++p) + delete p->second; + } + + // Size of this in number of bytes. + size_t + size() const; + + // Name of this written vendor subsection. + const char* + name() const + { + return (this->vendor_ == Object_attribute::OBJ_ATTR_PROC + ? parameters->target().attributes_vendor() + : "gnu"); + } + + // Return an array of known attributes. + Object_attribute* + known_attributes() + { return &this->known_attributes_[0]; } + + const Object_attribute* + known_attributes() const + { return &this->known_attributes_[0]; } + + typedef std::map Other_attributes; + + // Return attributes other than the known ones. + Other_attributes* + other_attributes() + { return &this->other_attributes_; } + + const Other_attributes* + other_attributes() const + { return &this->other_attributes_; } + + // Return a new attribute associated with TAG. + Object_attribute* + new_attribute(int tag); + + // Get an attribute + Object_attribute* + get_attribute(int tag); + + const Object_attribute* + get_attribute(int tag) const; + + // Write to BUFFER. + void + write(std::vector* buffer) const; + + private: + // Vendor of the object attributes. + int vendor_; + // Attributes with known tags. There are store in an array for fast + // access. + Object_attribute known_attributes_[NUM_KNOWN_ATTRIBUTES]; + // Attributes with known tags. There are stored in a sorted container. + Other_attributes other_attributes_; +}; + +// This class contains contents of an attributes section. + +class Attributes_section_data +{ + public: + // Construct an Attributes_section_data object by parsing section contents + // in VIEW of SIZE. + Attributes_section_data(const unsigned char* view, section_size_type size); + + // Copying constructor. + Attributes_section_data(const Attributes_section_data& asd) + { + for (int vendor = Object_attribute::OBJ_ATTR_FIRST; + vendor <= Object_attribute::OBJ_ATTR_LAST; + ++vendor) + this->vendor_object_attributes_[vendor] = + new Vendor_object_attributes(*asd.vendor_object_attributes_[vendor]); + } + + ~Attributes_section_data() + { + for (int vendor = Object_attribute::OBJ_ATTR_FIRST; + vendor <= Object_attribute::OBJ_ATTR_LAST; + ++vendor) + delete this->vendor_object_attributes_[vendor]; + } + + // Return the size of this as number of bytes. + size_t + size() const; + + // Return an array of known attributes. + Object_attribute* + known_attributes(int vendor) + { + gold_assert(vendor >= OBJ_ATTR_FIRST && vendor <= OBJ_ATTR_LAST); + return this->vendor_object_attributes_[vendor]->known_attributes(); + } + + const Object_attribute* + known_attributes(int vendor) const + { + gold_assert(vendor >= OBJ_ATTR_FIRST && vendor <= OBJ_ATTR_LAST); + return this->vendor_object_attributes_[vendor]->known_attributes(); + } + + // Return the other attributes. + Vendor_object_attributes::Other_attributes* + other_attributes(int vendor) + { + gold_assert(vendor >= OBJ_ATTR_FIRST && vendor <= OBJ_ATTR_LAST); + return this->vendor_object_attributes_[vendor]->other_attributes(); + } + + // Return the other attributes. + const Vendor_object_attributes::Other_attributes* + other_attributes(int vendor) const + { + gold_assert(vendor >= OBJ_ATTR_FIRST && vendor <= OBJ_ATTR_LAST); + return this->vendor_object_attributes_[vendor]->other_attributes(); + } + + // Return an attribute. + Object_attribute* + get_attribute(int vendor, int tag) + { + gold_assert(vendor >= OBJ_ATTR_FIRST && vendor <= OBJ_ATTR_LAST); + return this->vendor_object_attributes_[vendor]->get_attribute(tag); + } + + const Object_attribute* + get_attribute(int vendor, int tag) const + { + gold_assert(vendor >= OBJ_ATTR_FIRST && vendor <= OBJ_ATTR_LAST); + return this->vendor_object_attributes_[vendor]->get_attribute(tag); + } + + // Merge target-independent attributes from another Attributes_section_data + // of an object called NAME. + void + merge(const char* name, const Attributes_section_data* pasd); + + // Write to byte stream in an unsigned char vector. + void + write(std::vector*) const; + + private: + // For convenience. + static const int OBJ_ATTR_FIRST = Object_attribute::OBJ_ATTR_FIRST; + static const int OBJ_ATTR_LAST = Object_attribute::OBJ_ATTR_LAST; + + // Vendor object attributes. + Vendor_object_attributes* vendor_object_attributes_[OBJ_ATTR_LAST+1]; +}; + +// This class is used for writing out an Attribute_section_data. + +class Output_attributes_section_data : public Output_section_data +{ + public: + Output_attributes_section_data(const Attributes_section_data& asd) + : Output_section_data(1), attributes_section_data_(asd) + { } + + protected: + // Write the data to the output file. + void + do_write(Output_file*); + + // Set final data size. + void + set_final_data_size() + { this->set_data_size(attributes_section_data_.size()); } + + private: + // Attributes_section_data corresponding to this. + const Attributes_section_data& attributes_section_data_; +}; + +} // End namespace gold. + +#endif // !defined(GOLD_ATTRIBUTES_H) diff --git a/binutils-2.25/gold/binary.cc b/binutils-2.25/gold/binary.cc new file mode 100644 index 00000000..6cc99a96 --- /dev/null +++ b/binutils-2.25/gold/binary.cc @@ -0,0 +1,363 @@ +// binary.cc -- binary input files for gold + +// Copyright 2008 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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 +#include +#include "safe-ctype.h" + +#include "elfcpp.h" +#include "stringpool.h" +#include "fileread.h" +#include "output.h" +#include "binary.h" + +// Support for reading binary files as input. These become blobs in +// the final output. These files are treated as though they have a +// single .data section and define three symbols: +// _binary_FILENAME_start, _binary_FILENAME_end, _binary_FILENAME_size. +// The FILENAME is the name of the input file, with any +// non-alphanumeric character changed to an underscore. + +// We implement this by creating an ELF file in memory. + +namespace gold +{ + +// class Binary_to_elf. + +Binary_to_elf::Binary_to_elf(elfcpp::EM machine, int size, bool big_endian, + const std::string& filename) + : elf_machine_(machine), size_(size), big_endian_(big_endian), + filename_(filename), data_(NULL), filesize_(0) +{ +} + +Binary_to_elf::~Binary_to_elf() +{ + if (this->data_ != NULL) + delete[] this->data_; +} + +// Given FILENAME, create a buffer which looks like an ELF file with +// the contents of FILENAME as the contents of the only section. The +// TASK parameters is mainly for debugging, and records who holds +// locks. + +bool +Binary_to_elf::convert(const Task* task) +{ + if (this->size_ == 32) + { + if (!this->big_endian_) + { +#ifdef HAVE_TARGET_32_LITTLE + return this->sized_convert<32, false>(task); +#else + gold_unreachable(); +#endif + } + else + { +#ifdef HAVE_TARGET_32_BIG + return this->sized_convert<32, true>(task); +#else + gold_unreachable(); +#endif + } + } + else if (this->size_ == 64) + { + if (!this->big_endian_) + { +#ifdef HAVE_TARGET_64_LITTLE + return this->sized_convert<64, false>(task); +#else + gold_unreachable(); +#endif + } + else + { +#ifdef HAVE_TARGET_64_BIG + return this->sized_convert<64, true>(task); +#else + gold_unreachable(); +#endif + } + } + else + gold_unreachable(); +} + +// We are going to create: +// * The ELF file header. +// * Five sections: null section, .data, .symtab, .strtab, .shstrtab +// * The contents of the file. +// * Four symbols: null, begin, end, size. +// * Three symbol names. +// * Four section names. + +template +bool +Binary_to_elf::sized_convert(const Task* task) +{ + // Read the input file. + + File_read f; + if (!f.open(task, this->filename_)) + { + gold_error(_("cannot open %s: %s:"), this->filename_.c_str(), + strerror(errno)); + return false; + } + + section_size_type filesize = convert_to_section_size_type(f.filesize()); + const unsigned char* fileview; + if (filesize == 0) + fileview = NULL; + else + fileview = f.get_view(0, 0, filesize, false, false); + + unsigned int align; + if (size == 32) + align = 4; + else if (size == 64) + align = 8; + else + gold_unreachable(); + section_size_type aligned_filesize = align_address(filesize, align); + + // Build the stringpool for the symbol table. + + std::string mangled_name = this->filename_; + for (std::string::iterator p = mangled_name.begin(); + p != mangled_name.end(); + ++p) + if (!ISALNUM(*p)) + *p = '_'; + mangled_name = "_binary_" + mangled_name; + std::string start_symbol_name = mangled_name + "_start"; + std::string end_symbol_name = mangled_name + "_end"; + std::string size_symbol_name = mangled_name + "_size"; + + Stringpool strtab; + strtab.add(start_symbol_name.c_str(), false, NULL); + strtab.add(end_symbol_name.c_str(), false, NULL); + strtab.add(size_symbol_name.c_str(), false, NULL); + strtab.set_string_offsets(); + + // Build the stringpool for the section name table. + + Stringpool shstrtab; + shstrtab.add(".data", false, NULL); + shstrtab.add(".symtab", false, NULL); + shstrtab.add(".strtab", false, NULL); + shstrtab.add(".shstrtab", false, NULL); + shstrtab.set_string_offsets(); + + // Work out the size of the generated file, and the offsets of the + // various sections, and allocate a buffer. + + const int sym_size = elfcpp::Elf_sizes::sym_size; + + size_t output_size = (elfcpp::Elf_sizes::ehdr_size + + 5 * elfcpp::Elf_sizes::shdr_size); + size_t data_offset = output_size; + output_size += aligned_filesize; + size_t symtab_offset = output_size; + output_size += 4 * sym_size; + size_t strtab_offset = output_size; + output_size += strtab.get_strtab_size(); + size_t shstrtab_offset = output_size; + output_size += shstrtab.get_strtab_size(); + + unsigned char* buffer = new unsigned char[output_size]; + + // Write out the data. + + unsigned char* pout = buffer; + + this->write_file_header(&pout); + + this->write_section_header("", &shstrtab, elfcpp::SHT_NULL, + 0, 0, 0, 0, 0, + 0, 0, &pout); + // Having the section be named ".data", having it be writable, and + // giving it an alignment of 1 is because the GNU linker does it + // that way, and existing linker script expect it. + this->write_section_header(".data", &shstrtab, + elfcpp::SHT_PROGBITS, + (elfcpp::SHF_ALLOC + | elfcpp::SHF_WRITE), + data_offset, + filesize, 0, 0, + 1, 0, &pout); + this->write_section_header(".symtab", &shstrtab, + elfcpp::SHT_SYMTAB, + 0, symtab_offset, 4 * sym_size, + 3, 1, align, sym_size, &pout); + this->write_section_header(".strtab", &shstrtab, + elfcpp::SHT_STRTAB, + 0, strtab_offset, + strtab.get_strtab_size(), + 0, 0, 1, 0, &pout); + this->write_section_header(".shstrtab", &shstrtab, + elfcpp::SHT_STRTAB, + 0, shstrtab_offset, + shstrtab.get_strtab_size(), + 0, 0, 1, 0, &pout); + + if (filesize > 0) + { + memcpy(pout, fileview, filesize); + pout += filesize; + memset(pout, 0, aligned_filesize - filesize); + pout += aligned_filesize - filesize; + } + + this->write_symbol("", &strtab, 0, 0, &pout); + this->write_symbol(start_symbol_name, &strtab, 0, 1, + &pout); + this->write_symbol(end_symbol_name, &strtab, filesize, 1, + &pout); + this->write_symbol(size_symbol_name, &strtab, filesize, + elfcpp::SHN_ABS, &pout); + + strtab.write_to_buffer(pout, strtab.get_strtab_size()); + pout += strtab.get_strtab_size(); + + shstrtab.write_to_buffer(pout, shstrtab.get_strtab_size()); + pout += shstrtab.get_strtab_size(); + + gold_assert(static_cast(pout - buffer) == output_size); + + this->data_ = buffer; + this->filesize_ = output_size; + + f.unlock(task); + + return true; +} + +// Write out the file header. + +template +void +Binary_to_elf::write_file_header(unsigned char** ppout) +{ + elfcpp::Ehdr_write oehdr(*ppout); + + unsigned char e_ident[elfcpp::EI_NIDENT]; + memset(e_ident, 0, elfcpp::EI_NIDENT); + e_ident[elfcpp::EI_MAG0] = elfcpp::ELFMAG0; + e_ident[elfcpp::EI_MAG1] = elfcpp::ELFMAG1; + e_ident[elfcpp::EI_MAG2] = elfcpp::ELFMAG2; + e_ident[elfcpp::EI_MAG3] = elfcpp::ELFMAG3; + if (size == 32) + e_ident[elfcpp::EI_CLASS] = elfcpp::ELFCLASS32; + else if (size == 64) + e_ident[elfcpp::EI_CLASS] = elfcpp::ELFCLASS64; + else + gold_unreachable(); + e_ident[elfcpp::EI_DATA] = (big_endian + ? elfcpp::ELFDATA2MSB + : elfcpp::ELFDATA2LSB); + e_ident[elfcpp::EI_VERSION] = elfcpp::EV_CURRENT; + oehdr.put_e_ident(e_ident); + + oehdr.put_e_type(elfcpp::ET_REL); + oehdr.put_e_machine(this->elf_machine_); + oehdr.put_e_version(elfcpp::EV_CURRENT); + oehdr.put_e_entry(0); + oehdr.put_e_phoff(0); + oehdr.put_e_shoff(elfcpp::Elf_sizes::ehdr_size); + oehdr.put_e_flags(0); + oehdr.put_e_ehsize(elfcpp::Elf_sizes::ehdr_size); + oehdr.put_e_phentsize(0); + oehdr.put_e_phnum(0); + oehdr.put_e_shentsize(elfcpp::Elf_sizes::shdr_size); + oehdr.put_e_shnum(5); + oehdr.put_e_shstrndx(4); + + *ppout += elfcpp::Elf_sizes::ehdr_size; +} + +// Write out a section header. + +template +void +Binary_to_elf::write_section_header( + const char* name, + const Stringpool* shstrtab, + elfcpp::SHT type, + unsigned int flags, + section_size_type offset, + section_size_type section_size, + unsigned int link, + unsigned int info, + unsigned int addralign, + unsigned int entsize, + unsigned char** ppout) +{ + elfcpp::Shdr_write oshdr(*ppout); + + oshdr.put_sh_name(*name == '\0' ? 0 : shstrtab->get_offset(name)); + oshdr.put_sh_type(type); + oshdr.put_sh_flags(flags); + oshdr.put_sh_addr(0); + oshdr.put_sh_offset(offset); + oshdr.put_sh_size(section_size); + oshdr.put_sh_link(link); + oshdr.put_sh_info(info); + oshdr.put_sh_addralign(addralign); + oshdr.put_sh_entsize(entsize); + + *ppout += elfcpp::Elf_sizes::shdr_size; +} + +// Write out a symbol. + +template +void +Binary_to_elf::write_symbol( + const std::string& name, + const Stringpool* strtab, + section_size_type value, + unsigned int shndx, + unsigned char** ppout) +{ + unsigned char* pout = *ppout; + + elfcpp::Sym_write osym(pout); + osym.put_st_name(name.empty() ? 0 : strtab->get_offset(name.c_str())); + osym.put_st_value(value); + osym.put_st_size(0); + osym.put_st_info(name.empty() ? elfcpp::STB_LOCAL : elfcpp::STB_GLOBAL, + elfcpp::STT_NOTYPE); + osym.put_st_other(elfcpp::STV_DEFAULT, 0); + osym.put_st_shndx(shndx); + + *ppout += elfcpp::Elf_sizes::sym_size; +} + +} // End namespace gold. diff --git a/binutils-2.25/gold/binary.h b/binutils-2.25/gold/binary.h new file mode 100644 index 00000000..75bc731e --- /dev/null +++ b/binutils-2.25/gold/binary.h @@ -0,0 +1,116 @@ +// binary.h -- binary input files for gold -*- C++ -*- + +// Copyright 2008 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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. + +// Support binary input files by making them look like an ELF file. + +#ifndef GOLD_BINARY_H +#define GOLD_BINARY_H + +#include + +#include "elfcpp.h" + +namespace gold +{ + +class Task; + +template +class Stringpool_template; + +// This class takes a file name and creates a buffer which looks like +// an ELF file read into memory. + +class Binary_to_elf +{ + public: + Binary_to_elf(elfcpp::EM machine, int size, bool big_endian, + const std::string& filename); + + ~Binary_to_elf(); + + // Read contents and create an ELF buffer. Return true if this + // succeeds, false otherwise. + bool + convert(const Task*); + + // Return a pointer to the contents of the ELF file. + const unsigned char* + converted_data() const + { return this->data_; } + + // Return a pointer to the contents of the ELF file and let the + // caller take charge of it. It was allocated using new[]. + unsigned char* + converted_data_leak() + { + unsigned char* ret = this->data_; + this->data_ = NULL; + return ret; + } + + // Return the size of the ELF file. + size_t + converted_size() const + { return this->filesize_; } + + private: + Binary_to_elf(const Binary_to_elf&); + Binary_to_elf& operator=(const Binary_to_elf&); + + template + bool + sized_convert(const Task*); + + template + void + write_file_header(unsigned char**); + + template + void + write_section_header(const char*, const Stringpool_template*, + elfcpp::SHT, unsigned int, section_size_type, + section_size_type, unsigned int, unsigned int, + unsigned int, unsigned int, unsigned char**); + + template + void + write_symbol(const std::string&, const Stringpool_template*, + section_size_type, unsigned int, unsigned char**); + + // The ELF machine code of the file to create. + elfcpp::EM elf_machine_; + // The size of the file to create, 32 or 64. + int size_; + // Whether to create a big endian file. + bool big_endian_; + // The name of the file to read. + std::string filename_; + // The ELF file data, allocated by new []. + unsigned char* data_; + // The ELF file size. + section_size_type filesize_; +}; + +} // End namespace gold. + +#endif // !defined(GOLD_BINARY_H) diff --git a/binutils-2.25/gold/common.cc b/binutils-2.25/gold/common.cc new file mode 100644 index 00000000..b0c7d6e2 --- /dev/null +++ b/binutils-2.25/gold/common.cc @@ -0,0 +1,365 @@ +// common.cc -- handle common symbols for gold + +// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012 +// Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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 + +#include "workqueue.h" +#include "mapfile.h" +#include "layout.h" +#include "output.h" +#include "symtab.h" +#include "common.h" + +namespace gold +{ + +// Allocate_commons_task methods. + +// This task allocates the common symbols. We arrange to run it +// before anything else which needs to access the symbol table. + +Task_token* +Allocate_commons_task::is_runnable() +{ + return NULL; +} + +// Release a blocker. + +void +Allocate_commons_task::locks(Task_locker* tl) +{ + tl->add(this, this->blocker_); +} + +// Allocate the common symbols. + +void +Allocate_commons_task::run(Workqueue*) +{ + this->symtab_->allocate_commons(this->layout_, this->mapfile_); +} + +// This class is used to sort the common symbol. We normally put the +// larger common symbols first. This can be changed by using +// --sort-commons, which tells the linker to sort by alignment. + +template +class Sort_commons +{ + public: + Sort_commons(const Symbol_table* symtab, + Symbol_table::Sort_commons_order sort_order) + : symtab_(symtab), sort_order_(sort_order) + { } + + bool operator()(const Symbol* a, const Symbol* b) const; + + private: + // The symbol table. + const Symbol_table* symtab_; + // How to sort. + Symbol_table::Sort_commons_order sort_order_; +}; + +template +bool +Sort_commons::operator()(const Symbol* pa, const Symbol* pb) const +{ + if (pa == NULL) + return false; + if (pb == NULL) + return true; + + const Symbol_table* symtab = this->symtab_; + const Sized_symbol* psa = symtab->get_sized_symbol(pa); + const Sized_symbol* psb = symtab->get_sized_symbol(pb); + + // The size. + typename Sized_symbol::Size_type sa = psa->symsize(); + typename Sized_symbol::Size_type sb = psb->symsize(); + + // The alignment. + typename Sized_symbol::Value_type aa = psa->value(); + typename Sized_symbol::Value_type ab = psb->value(); + + if (this->sort_order_ == Symbol_table::SORT_COMMONS_BY_ALIGNMENT_DESCENDING) + { + if (aa < ab) + return false; + else if (ab < aa) + return true; + } + else if (this->sort_order_ + == Symbol_table::SORT_COMMONS_BY_ALIGNMENT_ASCENDING) + { + if (aa < ab) + return true; + else if (ab < aa) + return false; + } + else + gold_assert(this->sort_order_ + == Symbol_table::SORT_COMMONS_BY_SIZE_DESCENDING); + + // Sort by descending size. + if (sa < sb) + return false; + else if (sb < sa) + return true; + + if (this->sort_order_ == Symbol_table::SORT_COMMONS_BY_SIZE_DESCENDING) + { + // When the symbols are the same size, we sort them by + // alignment, largest alignment first. + if (aa < ab) + return false; + else if (ab < aa) + return true; + } + + // Otherwise we stabilize the sort by sorting by name. + return strcmp(psa->name(), psb->name()) < 0; +} + +// Allocate the common symbols. + +void +Symbol_table::allocate_commons(Layout* layout, Mapfile* mapfile) +{ + Sort_commons_order sort_order; + if (!parameters->options().user_set_sort_common()) + sort_order = SORT_COMMONS_BY_SIZE_DESCENDING; + else + { + const char* order = parameters->options().sort_common(); + if (*order == '\0' || strcmp(order, "descending") == 0) + sort_order = SORT_COMMONS_BY_ALIGNMENT_DESCENDING; + else if (strcmp(order, "ascending") == 0) + sort_order = SORT_COMMONS_BY_ALIGNMENT_ASCENDING; + else + { + gold_error("invalid --sort-common argument: %s", order); + sort_order = SORT_COMMONS_BY_SIZE_DESCENDING; + } + } + + if (parameters->target().get_size() == 32) + { +#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG) + this->do_allocate_commons<32>(layout, mapfile, sort_order); +#else + gold_unreachable(); +#endif + } + else if (parameters->target().get_size() == 64) + { +#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG) + this->do_allocate_commons<64>(layout, mapfile, sort_order); +#else + gold_unreachable(); +#endif + } + else + gold_unreachable(); +} + +// Allocated the common symbols, sized version. + +template +void +Symbol_table::do_allocate_commons(Layout* layout, Mapfile* mapfile, + Sort_commons_order sort_order) +{ + if (!this->commons_.empty()) + this->do_allocate_commons_list(layout, COMMONS_NORMAL, + &this->commons_, mapfile, + sort_order); + if (!this->tls_commons_.empty()) + this->do_allocate_commons_list(layout, COMMONS_TLS, + &this->tls_commons_, mapfile, + sort_order); + if (!this->small_commons_.empty()) + this->do_allocate_commons_list(layout, COMMONS_SMALL, + &this->small_commons_, mapfile, + sort_order); + if (!this->large_commons_.empty()) + this->do_allocate_commons_list(layout, COMMONS_LARGE, + &this->large_commons_, mapfile, + sort_order); +} + +// Allocate the common symbols in a list. IS_TLS indicates whether +// these are TLS common symbols. + +template +void +Symbol_table::do_allocate_commons_list( + Layout* layout, + Commons_section_type commons_section_type, + Commons_type* commons, + Mapfile* mapfile, + Sort_commons_order sort_order) +{ + // We've kept a list of all the common symbols. But the symbol may + // have been resolved to a defined symbol by now. And it may be a + // forwarder. First remove all non-common symbols. + bool any = false; + uint64_t addralign = 0; + for (Commons_type::iterator p = commons->begin(); + p != commons->end(); + ++p) + { + Symbol* sym = *p; + if (sym->is_forwarder()) + { + sym = this->resolve_forwards(sym); + *p = sym; + } + if (!sym->is_common()) + *p = NULL; + else + { + any = true; + Sized_symbol* ssym = this->get_sized_symbol(sym); + if (ssym->value() > addralign) + addralign = ssym->value(); + } + } + if (!any) + return; + + // Sort the common symbols. + std::sort(commons->begin(), commons->end(), + Sort_commons(this, sort_order)); + + // Place them in a newly allocated BSS section. + elfcpp::Elf_Xword flags = elfcpp::SHF_WRITE | elfcpp::SHF_ALLOC; + const char* name; + const char* ds_name; + switch (commons_section_type) + { + case COMMONS_NORMAL: + name = ".bss"; + ds_name = "** common"; + break; + case COMMONS_TLS: + flags |= elfcpp::SHF_TLS; + name = ".tbss"; + ds_name = "** tls common"; + break; + case COMMONS_SMALL: + flags |= parameters->target().small_common_section_flags(); + name = ".sbss"; + ds_name = "** small common"; + break; + case COMMONS_LARGE: + flags |= parameters->target().large_common_section_flags(); + name = ".lbss"; + ds_name = "** large common"; + break; + default: + gold_unreachable(); + } + + Output_data_space* poc; + Output_section* os; + + if (!parameters->incremental_update()) + { + poc = new Output_data_space(addralign, ds_name); + os = layout->add_output_section_data(name, elfcpp::SHT_NOBITS, flags, + poc, ORDER_INVALID, false); + } + else + { + // When doing an incremental update, we need to allocate each common + // directly from the output section's free list. + poc = NULL; + os = layout->find_output_section(name); + } + + if (os != NULL) + { + if (commons_section_type == COMMONS_SMALL) + os->set_is_small_section(); + else if (commons_section_type == COMMONS_LARGE) + os->set_is_large_section(); + } + + // Allocate them all. + + off_t off = 0; + for (Commons_type::iterator p = commons->begin(); + p != commons->end(); + ++p) + { + Symbol* sym = *p; + if (sym == NULL) + break; + + // Because we followed forwarding symbols above, but we didn't + // do it reliably before adding symbols to the list, it is + // possible for us to have the same symbol on the list twice. + // This can happen in the horrible case where a program defines + // a common symbol with the same name as a versioned libc + // symbol. That will show up here as a symbol which has already + // been allocated and is therefore no longer a common symbol. + if (!sym->is_common()) + continue; + + Sized_symbol* ssym = this->get_sized_symbol(sym); + + // Record the symbol in the map file now, before we change its + // value. Pass the size in separately so that we don't have to + // templatize the map code, which is not performance sensitive. + if (mapfile != NULL) + mapfile->report_allocate_common(sym, ssym->symsize()); + + if (poc != NULL) + { + off = align_address(off, ssym->value()); + ssym->allocate_common(poc, off); + off += ssym->symsize(); + } + else + { + // For an incremental update, allocate from the free list. + off = os->allocate(ssym->symsize(), ssym->value()); + if (off == -1) + gold_fallback(_("out of patch space in section %s; " + "relink with --incremental-full"), + os->name()); + ssym->allocate_common(os, off); + } + } + + if (poc != NULL) + poc->set_current_data_size(off); + + commons->clear(); +} + +} // End namespace gold. diff --git a/binutils-2.25/gold/common.h b/binutils-2.25/gold/common.h new file mode 100644 index 00000000..4de585c3 --- /dev/null +++ b/binutils-2.25/gold/common.h @@ -0,0 +1,67 @@ +// common.h -- handle common symbols for gold -*- C++ -*- + +// Copyright 2006, 2007, 2008, 2010 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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. + +#ifndef GOLD_COMMON_H +#define GOLD_COMMON_H + +#include "workqueue.h" + +namespace gold +{ + +class Symbol_table; + +// This task is used to allocate the common symbols. + +class Allocate_commons_task : public Task +{ + public: + Allocate_commons_task(Symbol_table* symtab, Layout* layout, Mapfile* mapfile, + Task_token* blocker) + : symtab_(symtab), layout_(layout), mapfile_(mapfile), blocker_(blocker) + { } + + // The standard Task methods. + + Task_token* + is_runnable(); + + void + locks(Task_locker*); + + void + run(Workqueue*); + + std::string + get_name() const + { return "Allocate_commons_task"; } + + private: + Symbol_table* symtab_; + Layout* layout_; + Mapfile* mapfile_; + Task_token* blocker_; +}; + +} // End namespace gold. + +#endif // !defined(GOLD_COMMON_H) diff --git a/binutils-2.25/gold/compressed_output.cc b/binutils-2.25/gold/compressed_output.cc new file mode 100644 index 00000000..9c7c7dd7 --- /dev/null +++ b/binutils-2.25/gold/compressed_output.cc @@ -0,0 +1,247 @@ +// compressed_output.cc -- manage compressed debug sections for gold + +// Copyright 2007, 2008, 2010 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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" + +#ifdef HAVE_ZLIB_H +#include +#endif + +#include "parameters.h" +#include "options.h" +#include "compressed_output.h" + +namespace gold +{ + +#ifdef HAVE_ZLIB_H + +// Compress UNCOMPRESSED_DATA of size UNCOMPRESSED_SIZE. Returns true +// if it successfully compressed, false if it failed for any reason +// (including not having zlib support in the library). If it returns +// true, it allocates memory for the compressed data using new, and +// sets *COMPRESSED_DATA and *COMPRESSED_SIZE to appropriate values. +// It also writes a header before COMPRESSED_DATA: 4 bytes saying +// "ZLIB", and 8 bytes indicating the uncompressed size, in big-endian +// order. + +static bool +zlib_compress(const unsigned char* uncompressed_data, + unsigned long uncompressed_size, + unsigned char** compressed_data, + unsigned long* compressed_size) +{ + const int header_size = 12; + *compressed_size = uncompressed_size + uncompressed_size / 1000 + 128; + *compressed_data = new unsigned char[*compressed_size + header_size]; + + int compress_level; + if (parameters->options().optimize() >= 1) + compress_level = 9; + else + compress_level = 1; + + int rc = compress2(reinterpret_cast(*compressed_data) + header_size, + compressed_size, + reinterpret_cast(uncompressed_data), + uncompressed_size, + compress_level); + if (rc == Z_OK) + { + memcpy(*compressed_data, "ZLIB", 4); + elfcpp::Swap_unaligned<64, true>::writeval(*compressed_data + 4, + uncompressed_size); + *compressed_size += header_size; + return true; + } + else + { + delete[] *compressed_data; + *compressed_data = NULL; + return false; + } +} + +// Decompress COMPRESSED_DATA of size COMPRESSED_SIZE, into a buffer +// UNCOMPRESSED_DATA of size UNCOMPRESSED_SIZE. Returns TRUE if it +// decompressed successfully, false if it failed. The buffer, of +// appropriate size, is provided by the caller, and is typically part +// of the memory-mapped output file. + +static bool +zlib_decompress(const unsigned char* compressed_data, + unsigned long compressed_size, + unsigned char* uncompressed_data, + unsigned long uncompressed_size) +{ + z_stream strm; + int rc; + + /* It is possible the section consists of several compressed + buffers concatenated together, so we uncompress in a loop. */ + strm.zalloc = NULL; + strm.zfree = NULL; + strm.opaque = NULL; + strm.avail_in = compressed_size; + strm.next_in = const_cast(compressed_data); + strm.avail_out = uncompressed_size; + + rc = inflateInit(&strm); + while (strm.avail_in > 0) + { + if (rc != Z_OK) + return false; + strm.next_out = ((Bytef*) uncompressed_data + + (uncompressed_size - strm.avail_out)); + rc = inflate(&strm, Z_FINISH); + if (rc != Z_STREAM_END) + return false; + rc = inflateReset(&strm); + } + rc = inflateEnd(&strm); + if (rc != Z_OK || strm.avail_out != 0) + return false; + + return true; +} + +#else // !defined(HAVE_ZLIB_H) + +static bool +zlib_compress(const unsigned char*, unsigned long, + unsigned char**, unsigned long*) +{ + return false; +} + +static bool +zlib_decompress(const unsigned char*, unsigned long, + unsigned char*, unsigned long) +{ + return false; +} + +#endif // !defined(HAVE_ZLIB_H) + +// Read the compression header of a compressed debug section and return +// the uncompressed size. + +uint64_t +get_uncompressed_size(const unsigned char* compressed_data, + section_size_type compressed_size) +{ + const unsigned int zlib_header_size = 12; + + /* Verify the compression header. Currently, we support only zlib + compression, so it should be "ZLIB" followed by the uncompressed + section size, 8 bytes in big-endian order. */ + if (compressed_size >= zlib_header_size + && strncmp(reinterpret_cast(compressed_data), + "ZLIB", 4) == 0) + return elfcpp::Swap_unaligned<64, true>::readval(compressed_data + 4); + return -1ULL; +} + +// Decompress a compressed debug section directly into the output file. + +bool +decompress_input_section(const unsigned char* compressed_data, + unsigned long compressed_size, + unsigned char* uncompressed_data, + unsigned long uncompressed_size) +{ + const unsigned int zlib_header_size = 12; + + /* Verify the compression header. Currently, we support only zlib + compression, so it should be "ZLIB" followed by the uncompressed + section size, 8 bytes in big-endian order. */ + if (compressed_size >= zlib_header_size + && strncmp(reinterpret_cast(compressed_data), + "ZLIB", 4) == 0) + { + unsigned long uncompressed_size_check = + elfcpp::Swap_unaligned<64, true>::readval(compressed_data + 4); + gold_assert(uncompressed_size_check == uncompressed_size); + return zlib_decompress(compressed_data + zlib_header_size, + compressed_size - zlib_header_size, + uncompressed_data, + uncompressed_size); + } + return false; +} + +// Class Output_compressed_section. + +// Set the final data size of a compressed section. This is where +// we actually compress the section data. + +void +Output_compressed_section::set_final_data_size() +{ + off_t uncompressed_size = this->postprocessing_buffer_size(); + + // (Try to) compress the data. + unsigned long compressed_size; + unsigned char* uncompressed_data = this->postprocessing_buffer(); + + // At this point the contents of all regular input sections will + // have been copied into the postprocessing buffer, and relocations + // will have been applied. Now we need to copy in the contents of + // anything other than a regular input section. + this->write_to_postprocessing_buffer(); + + bool success = false; + if (strcmp(this->options_->compress_debug_sections(), "zlib") == 0) + success = zlib_compress(uncompressed_data, uncompressed_size, + &this->data_, &compressed_size); + if (success) + { + // This converts .debug_foo to .zdebug_foo + this->new_section_name_ = std::string(".z") + (this->name() + 1); + this->set_name(this->new_section_name_.c_str()); + this->set_data_size(compressed_size); + } + else + { + gold_warning(_("not compressing section data: zlib error")); + gold_assert(this->data_ == NULL); + this->set_data_size(uncompressed_size); + } +} + +// Write out a compressed section. If we couldn't compress, we just +// write it out as normal, uncompressed data. + +void +Output_compressed_section::do_write(Output_file* of) +{ + off_t offset = this->offset(); + off_t data_size = this->data_size(); + unsigned char* view = of->get_output_view(offset, data_size); + if (this->data_ == NULL) + memcpy(view, this->postprocessing_buffer(), data_size); + else + memcpy(view, this->data_, data_size); + of->write_output_view(offset, data_size, view); +} + +} // End namespace gold. diff --git a/binutils-2.25/gold/compressed_output.h b/binutils-2.25/gold/compressed_output.h new file mode 100644 index 00000000..2d6ebd95 --- /dev/null +++ b/binutils-2.25/gold/compressed_output.h @@ -0,0 +1,86 @@ +// compressed_output.h -- compressed output sections for gold -*- C++ -*- + +// Copyright 2007, 2008, 2010 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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. + +// We support compressing .debug_* sections on output. (And, +// potentially one day, other sections.) This is a form of +// relaxation. This file adds support for merging and emitting the +// compressed sections. + +#ifndef GOLD_COMPRESSED_OUTPUT_H +#define GOLD_COMPRESSED_OUTPUT_H + +#include + +#include "output.h" + +namespace gold +{ + +class General_options; + +// Read the compression header of a compressed debug section and return +// the uncompressed size. + +extern uint64_t +get_uncompressed_size(const unsigned char*, section_size_type); + +// Decompress a compressed debug section directly into the output file. + +extern bool +decompress_input_section(const unsigned char*, unsigned long, unsigned char*, + unsigned long); + +// This is used for a section whose data should be compressed. It is +// a regular Output_section which computes its contents into a buffer +// and then postprocesses it. + +class Output_compressed_section : public Output_section +{ + public: + Output_compressed_section(const General_options* options, + const char* name, elfcpp::Elf_Word flags, + elfcpp::Elf_Xword type) + : Output_section(name, flags, type), + options_(options) + { this->set_requires_postprocessing(); } + + protected: + // Set the final data size. + void + set_final_data_size(); + + // Write out the compressed contents. + void + do_write(Output_file*); + + private: + // The options--this includes the compression type. + const General_options* options_; + // The compressed data. + unsigned char* data_; + // The new section name if we do compress. + std::string new_section_name_; +}; + +} // End namespace gold. + +#endif // !defined(GOLD_COMPRESSED_OUTPUT_H) diff --git a/binutils-2.25/gold/config.in b/binutils-2.25/gold/config.in new file mode 100644 index 00000000..d46fd757 --- /dev/null +++ b/binutils-2.25/gold/config.in @@ -0,0 +1,277 @@ +/* config.in. Generated from configure.ac by autoheader. */ + +/* Check that config.h is #included before system headers + (this works only for glibc, but that should be enough). */ +#if defined(__GLIBC__) && !defined(__FreeBSD_kernel__) && !defined(__CONFIG_H__) +# error config.h must be #included before system headers +#endif +#define __CONFIG_H__ 1 + +/* Define if building universal (internal helper macro) */ +#undef AC_APPLE_UNIVERSAL_BUILD + +/* Define to 1 if translation of program messages to the user's native + language is requested. */ +#undef ENABLE_NLS + +/* Define to enable linker plugins */ +#undef ENABLE_PLUGINS + +/* Define to do multi-threaded linking */ +#undef ENABLE_THREADS + +/* Default big endian (true or false) */ +#undef GOLD_DEFAULT_BIG_ENDIAN + +/* Default machine code */ +#undef GOLD_DEFAULT_MACHINE + +/* Default OSABI code */ +#undef GOLD_DEFAULT_OSABI + +/* Default size (32 or 64) */ +#undef GOLD_DEFAULT_SIZE + +/* Define to 1 if you have the header file. */ +#undef HAVE_BYTESWAP_H + +/* Define to 1 if you have the `chsize' function. */ +#undef HAVE_CHSIZE + +/* Define to 1 if you have the declaration of `asprintf', and to 0 if you + don't. */ +#undef HAVE_DECL_ASPRINTF + +/* Define to 1 if you have the declaration of `basename', and to 0 if you + don't. */ +#undef HAVE_DECL_BASENAME + +/* Define to 1 if you have the declaration of `ffs', and to 0 if you don't. */ +#undef HAVE_DECL_FFS + +/* Define to 1 if you have the declaration of `memmem', and to 0 if you don't. + */ +#undef HAVE_DECL_MEMMEM + +/* Define to 1 if you have the declaration of `snprintf', and to 0 if you + don't. */ +#undef HAVE_DECL_SNPRINTF + +/* Define to 1 if you have the declaration of `strndup', and to 0 if you + don't. */ +#undef HAVE_DECL_STRNDUP + +/* Define to 1 if you have the declaration of `strverscmp', and to 0 if you + don't. */ +#undef HAVE_DECL_STRVERSCMP + +/* Define to 1 if you have the declaration of `vasprintf', and to 0 if you + don't. */ +#undef HAVE_DECL_VASPRINTF + +/* Define to 1 if you have the declaration of `vsnprintf', and to 0 if you + don't. */ +#undef HAVE_DECL_VSNPRINTF + +/* Define to 1 if you have the header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_EXT_HASH_MAP + +/* Define to 1 if you have the header file. */ +#undef HAVE_EXT_HASH_SET + +/* Define to 1 if you have the `fallocate' function. */ +#undef HAVE_FALLOCATE + +/* Define to 1 if you have the `ffsll' function. */ +#undef HAVE_FFSLL + +/* Define to 1 if you have the `ftruncate' function. */ +#undef HAVE_FTRUNCATE + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define if your file defines LC_MESSAGES. */ +#undef HAVE_LC_MESSAGES + +/* Define to 1 if you have the header file. */ +#undef HAVE_LOCALE_H + +/* Define to 1 if you have the `mallinfo' function. */ +#undef HAVE_MALLINFO + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `mmap' function. */ +#undef HAVE_MMAP + +/* Define to 1 if you have the mremap function with MREMAP_MAYMOVE support */ +#undef HAVE_MREMAP + +/* Define if compiler supports #pragma omp threadprivate */ +#undef HAVE_OMP_SUPPORT + +/* Define to 1 if you have the `posix_fallocate' function. */ +#undef HAVE_POSIX_FALLOCATE + +/* Define to 1 if you have the `pread' function. */ +#undef HAVE_PREAD + +/* Define to 1 if you have the `readv' function. */ +#undef HAVE_READV + +/* Define to 1 if you have the `setlocale' function. */ +#undef HAVE_SETLOCALE + +/* Define if struct stat has a field st_mtim with timespec for mtime */ +#undef HAVE_STAT_ST_MTIM + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `sysconf' function. */ +#undef HAVE_SYSCONF + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_MMAN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to support 32-bit big-endian targets */ +#undef HAVE_TARGET_32_BIG + +/* Define to support 32-bit little-endian targets */ +#undef HAVE_TARGET_32_LITTLE + +/* Define to support 64-bit big-endian targets */ +#undef HAVE_TARGET_64_BIG + +/* Define to support 64-bit little-endian targets */ +#undef HAVE_TARGET_64_LITTLE + +/* Define if attributes work on C++ templates */ +#undef HAVE_TEMPLATE_ATTRIBUTES + +/* Define to 1 if you have the `times' function. */ +#undef HAVE_TIMES + +/* Define if std::tr1::hash is usable */ +#undef HAVE_TR1_HASH_OFF_T + +/* Define to 1 if you have the header file. */ +#undef HAVE_TR1_UNORDERED_MAP + +/* Define if ::std::tr1::unordered_map::rehash is usable */ +#undef HAVE_TR1_UNORDERED_MAP_REHASH + +/* Define to 1 if you have the header file. */ +#undef HAVE_TR1_UNORDERED_SET + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_WINDOWS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ZLIB_H + +/* Default library search path */ +#undef LIB_PATH + +/* Whether configured as a native linker */ +#undef NATIVE_LINKER + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* System root for target files */ +#undef TARGET_SYSTEM_ROOT + +/* Whether the system root can be relocated */ +#undef TARGET_SYSTEM_ROOT_RELOCATABLE + +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# undef _ALL_SOURCE +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# undef _GNU_SOURCE +#endif +/* Enable threading extensions on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# undef _POSIX_PTHREAD_SEMANTICS +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# undef _TANDEM_SOURCE +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# undef __EXTENSIONS__ +#endif + + +/* Version number of package */ +#undef VERSION + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#if defined AC_APPLE_UNIVERSAL_BUILD +# if defined __BIG_ENDIAN__ +# define WORDS_BIGENDIAN 1 +# endif +#else +# ifndef WORDS_BIGENDIAN +# undef WORDS_BIGENDIAN +# endif +#endif + +/* Define to 1 if on MINIX. */ +#undef _MINIX + +/* Define to 2 if the system does not provide POSIX.1 features except with + this defined. */ +#undef _POSIX_1_SOURCE + +/* Define to 1 if you need to in order for `stat' and other things to work. */ +#undef _POSIX_SOURCE diff --git a/binutils-2.25/gold/configure b/binutils-2.25/gold/configure new file mode 100755 index 00000000..3ef8833f --- /dev/null +++ b/binutils-2.25/gold/configure @@ -0,0 +1,9195 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.64 for gold 0.1. +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software +# Foundation, Inc. +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 +test \$(( 1 + 1 )) = 2 || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + # We cannot yet assume a decent shell, so we have to provide a + # neutralization value for shells without unset; and this also + # works around shells that cannot unset nonexistent variables. + BASH_ENV=/dev/null + ENV=/dev/null + (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error ERROR [LINENO LOG_FD] +# --------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with status $?, using 1 if that was 0. +as_fn_error () +{ + as_status=$?; test $as_status -eq 0 && as_status=1 + if test "$3"; then + as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 + fi + $as_echo "$as_me: error: $1" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='gold' +PACKAGE_TARNAME='gold' +PACKAGE_VERSION='0.1' +PACKAGE_STRING='gold 0.1' +PACKAGE_BUGREPORT='' +PACKAGE_URL='' + +ac_unique_file="gold.cc" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='am__EXEEXT_FALSE +am__EXEEXT_TRUE +LTLIBOBJS +MAINT +MAINTAINER_MODE_FALSE +MAINTAINER_MODE_TRUE +HAVE_PUBNAMES_FALSE +HAVE_PUBNAMES_TRUE +DLOPEN_LIBS +CXXCPP +HAVE_ZLIB_FALSE +HAVE_ZLIB_TRUE +LIBOBJS +LFS_CFLAGS +GOLD_LDADD +GOLD_LDFLAGS +WARN_CXXFLAGS +NO_WERROR +WARN_CFLAGS +IFUNC_STATIC_FALSE +IFUNC_STATIC_TRUE +IFUNC_FALSE +IFUNC_TRUE +RANDOM_SEED_CFLAGS +TLS_DESCRIPTORS_FALSE +TLS_DESCRIPTORS_TRUE +TLS_GNU2_DIALECT_FALSE +TLS_GNU2_DIALECT_TRUE +OMP_SUPPORT_FALSE +OMP_SUPPORT_TRUE +STATIC_TLS_FALSE +STATIC_TLS_TRUE +TLS_FALSE +TLS_TRUE +MERGE_CONSTANTS_FLAG +MCMODEL_MEDIUM_FALSE +MCMODEL_MEDIUM_TRUE +FN_PTRS_IN_SO_WITHOUT_PIC_FALSE +FN_PTRS_IN_SO_WITHOUT_PIC_TRUE +HAVE_STATIC_FALSE +HAVE_STATIC_TRUE +NATIVE_OR_CROSS_LINKER_FALSE +NATIVE_OR_CROSS_LINKER_TRUE +GCC_FALSE +GCC_TRUE +NATIVE_LINKER_FALSE +NATIVE_LINKER_TRUE +MSGMERGE +MSGFMT +MKINSTALLDIRS +CATOBJEXT +GENCAT +INSTOBJEXT +DATADIRNAME +CATALOGS +POSUB +GMSGFMT +XGETTEXT +INCINTL +LIBINTL_DEP +LIBINTL +USE_NLS +EGREP +GREP +CPP +LN_S +RANLIB +YFLAGS +YACC +am__fastdepCXX_FALSE +am__fastdepCXX_TRUE +CXXDEPMODE +ac_ct_CXX +CXXFLAGS +CXX +am__fastdepCC_FALSE +am__fastdepCC_TRUE +CCDEPMODE +AMDEPBACKSLASH +AMDEP_FALSE +AMDEP_TRUE +am__quote +am__include +DEPDIR +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +NM +TARGETOBJS +DEFAULT_TARGET +DEFAULT_TARGET_TILEGX_FALSE +DEFAULT_TARGET_TILEGX_TRUE +DEFAULT_TARGET_X86_64_FALSE +DEFAULT_TARGET_X86_64_TRUE +DEFAULT_TARGET_SPARC_FALSE +DEFAULT_TARGET_SPARC_TRUE +DEFAULT_TARGET_POWERPC_FALSE +DEFAULT_TARGET_POWERPC_TRUE +DEFAULT_TARGET_I386_FALSE +DEFAULT_TARGET_I386_TRUE +DEFAULT_TARGET_ARM_FALSE +DEFAULT_TARGET_ARM_TRUE +PLUGINS_FALSE +PLUGINS_TRUE +THREADS_FALSE +THREADS_TRUE +installed_linker +install_as_default +am__untar +am__tar +AMTAR +am__leading_dot +SET_MAKE +AWK +mkdir_p +MKDIR_P +INSTALL_STRIP_PROGRAM +STRIP +install_sh +MAKEINFO +AUTOHEADER +AUTOMAKE +AUTOCONF +ACLOCAL +VERSION +PACKAGE +CYGPATH_W +am__isrc +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +target_os +target_vendor +target_cpu +target +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +with_sysroot +enable_gold +enable_threads +enable_plugins +enable_targets +with_lib_path +enable_dependency_tracking +enable_nls +enable_werror +enable_build_warnings +with_gold_ldflags +with_gold_ldadd +with_zlib +enable_maintainer_mode +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CXX +CXXFLAGS +CCC +YACC +YFLAGS +CPP +CXXCPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information." + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures gold 0.1 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/gold] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] + --target=TARGET configure for building compilers for TARGET [HOST] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of gold 0.1:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-gold[=ARG] build gold [ARG={default,yes,no}] + --enable-threads multi-threaded linking + --enable-plugins linker plugins + --enable-targets alternative target configurations + --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors + --disable-nls do not use Native Language Support + --enable-werror treat compile warnings as errors + --enable-build-warnings enable build-time compiler warnings + --enable-maintainer-mode enable make rules and dependencies not useful + (and sometimes confusing) to the casual installer + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-sysroot=DIR search for usr/lib et al within DIR + --with-lib-path=dir1:dir2... set default LIB_PATH + --with-gold-ldflags=FLAGS additional link flags for gold + --with-gold-ldadd=LIBS additional libraries for gold + --with-zlib include zlib support (auto/yes/no) default=auto + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CXX C++ compiler command + CXXFLAGS C++ compiler flags + YACC The `Yet Another C Compiler' implementation to use. Defaults to + the first program found out of: `bison -y', `byacc', `yacc'. + YFLAGS The list of arguments that will be passed by default to $YACC. + This script will default YFLAGS to the empty string to avoid a + default value of `-d' given by some make applications. + CPP C preprocessor + CXXCPP C++ preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to the package provider. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +gold configure 0.1 +generated by GNU Autoconf 2.64 + +Copyright (C) 2009 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + return $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_cxx_try_compile LINENO +# ---------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + return $ac_retval + +} # ac_fn_cxx_try_compile + +# ac_fn_c_try_cpp LINENO +# ---------------------- +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + return $ac_retval + +} # ac_fn_c_try_cpp + +# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_c_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_header_mongrel + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + return $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES +# ------------------------------------------------------- +# Tests whether HEADER exists and can be compiled using the include files in +# INCLUDES, setting the cache variable VAR accordingly. +ac_fn_c_check_header_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_header_compile + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + return $ac_retval + +} # ac_fn_c_try_link + +# ac_fn_c_check_func LINENO FUNC VAR +# ---------------------------------- +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_c_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_func + +# ac_fn_c_check_decl LINENO SYMBOL VAR +# ------------------------------------ +# Tests whether SYMBOL is declared, setting cache variable VAR accordingly. +ac_fn_c_check_decl () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + as_decl_name=`echo $2|sed 's/ *(.*//'` + as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 +$as_echo_n "checking whether $as_decl_name is declared... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +#ifndef $as_decl_name +#ifdef __cplusplus + (void) $as_decl_use; +#else + (void) $as_decl_name; +#endif +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_c_check_decl + +# ac_fn_cxx_try_cpp LINENO +# ------------------------ +# Try to preprocess conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_cpp () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + return $ac_retval + +} # ac_fn_cxx_try_cpp + +# ac_fn_cxx_check_header_mongrel LINENO HEADER VAR INCLUDES +# --------------------------------------------------------- +# Tests whether HEADER exists, giving a warning if it cannot be compiled using +# the include files in INCLUDES and setting the cache variable VAR +# accordingly. +ac_fn_cxx_check_header_mongrel () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +else + # Is the header compilable? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 +$as_echo_n "checking $2 usability... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +#include <$2> +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_header_compiler=yes +else + ac_header_compiler=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 +$as_echo "$ac_header_compiler" >&6; } + +# Is the header present? +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 +$as_echo_n "checking $2 presence... " >&6; } +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include <$2> +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + ac_header_preproc=yes +else + ac_header_preproc=no +fi +rm -f conftest.err conftest.$ac_ext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 +$as_echo "$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_cxx_preproc_warn_flag in #(( + yes:no: ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 +$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; + no:yes:* ) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 +$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 +$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 +$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 +$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 +$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} + ;; +esac + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + eval "$3=\$ac_header_compiler" +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_cxx_check_header_mongrel + +# ac_fn_cxx_try_link LINENO +# ------------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + return $ac_retval + +} # ac_fn_cxx_try_link + +# ac_fn_cxx_check_func LINENO FUNC VAR +# ------------------------------------ +# Tests whether FUNC exists, setting the cache variable VAR accordingly +ac_fn_cxx_check_func () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 +$as_echo_n "checking for $2... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +/* Define $2 to an innocuous variant, in case declares $2. + For example, HP-UX 11i declares gettimeofday. */ +#define $2 innocuous_$2 + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $2 (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $2 + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $2 (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$2 || defined __stub___$2 +choke me +#endif + +int +main () +{ +return $2 (); + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_cxx_check_func + +# ac_fn_cxx_check_decl LINENO SYMBOL VAR +# -------------------------------------- +# Tests whether SYMBOL is declared, setting cache variable VAR accordingly. +ac_fn_cxx_check_decl () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + as_decl_name=`echo $2|sed 's/ *(.*//'` + as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'` + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5 +$as_echo_n "checking whether $as_decl_name is declared... " >&6; } +if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$4 +int +main () +{ +#ifndef $as_decl_name +#ifdef __cplusplus + (void) $as_decl_use; +#else + (void) $as_decl_name; +#endif +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + eval "$3=yes" +else + eval "$3=no" +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +eval ac_res=\$$3 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 +$as_echo "$ac_res" >&6; } + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + +} # ac_fn_cxx_check_decl +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by gold $as_me 0.1, which was +generated by GNU Autoconf 2.64. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------------- ## +## File substitutions. ## +## ------------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + ac_site_file1=$CONFIG_SITE +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + + + + + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + for ac_t in install-sh install.sh shtool; do + if test -f "$ac_dir/$ac_t"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/$ac_t -c" + break 2 + fi + done +done +if test -z "$ac_aux_dir"; then + as_fn_error "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if test "${ac_cv_build+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if test "${ac_cv_host+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5 +$as_echo_n "checking target system type... " >&6; } +if test "${ac_cv_target+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "x$target_alias" = x; then + ac_cv_target=$ac_cv_host +else + ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` || + as_fn_error "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5 +$as_echo "$ac_cv_target" >&6; } +case $ac_cv_target in +*-*-*) ;; +*) as_fn_error "invalid value of canonical target" "$LINENO" 5;; +esac +target=$ac_cv_target +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_target +shift +target_cpu=$1 +target_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +target_os=$* +IFS=$ac_save_IFS +case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac + + +# The aliases save the names the user supplied, while $host etc. +# will get canonicalized. +test -n "$target_alias" && + test "$program_prefix$program_suffix$program_transform_name" = \ + NONENONEs,x,x, && + program_prefix=${target_alias}- + +am__api_version='1.11' + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 +$as_echo_n "checking whether build environment is sane... " >&6; } +# Just in case +sleep 1 +echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[\\\"\#\$\&\'\`$am_lf]*) + as_fn_error "unsafe absolute working directory name" "$LINENO" 5;; +esac +case $srcdir in + *[\\\"\#\$\&\'\`$am_lf\ \ ]*) + as_fn_error "unsafe srcdir value: \`$srcdir'" "$LINENO" 5;; +esac + +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + as_fn_error "ls -t appears to fail. Make sure there is not a broken +alias in your environment" "$LINENO" 5 + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + as_fn_error "newly created file is older than distributed files! +Check your system clock" "$LINENO" 5 +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. +# By default was `s,x,x', remove it if useless. +ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' +program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5 +$as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 +$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } +if test -z "$MKDIR_P"; then + if test "${ac_cv_path_mkdir+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue + case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir (GNU coreutils) '* | \ + 'mkdir (coreutils) '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + break 3;; + esac + done + done + done +IFS=$as_save_IFS + +fi + + if test "${ac_cv_path_mkdir+set}" = set; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use the slow shell script. Don't cache a + # value for MKDIR_P within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + test -d ./--version && rmdir ./--version + MKDIR_P="$ac_install_sh -d" + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 +$as_echo "$MKDIR_P" >&6; } + +mkdir_p="$MKDIR_P" +case $mkdir_p in + [\\/$]* | ?:[\\/]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_AWK+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + am__isrc=' -I$(srcdir)' + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + as_fn_error "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE='gold' + VERSION='0.1' + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +# Always define AMTAR for backward compatibility. + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' + + + + + + +ac_config_headers="$ac_config_headers config.h:config.in" + + +# PR 14072 + + + +# Check whether --with-sysroot was given. +if test "${with_sysroot+set}" = set; then : + withval=$with_sysroot; sysroot=$withval +else + sysroot=no +fi + + +if test "$sysroot" = "yes"; then + sysroot='${exec_prefix}/${target_alias}/sys-root' +elif test "$sysroot" = "no"; then + sysroot= +fi + +sysroot_relocatable=0 +if test -n "$sysroot"; then + case "sysroot" in + "${prefix}" | "${prefix}/"* | \ + "${exec_prefix}" | "${exec_prefix}/"* | \ + '${prefix}' | '${prefix}/'*| \ + '${exec_prefix}' | '${exec_prefix}/'*) + sysroot_relocatable=1 + ;; + esac +fi + + +cat >>confdefs.h <<_ACEOF +#define TARGET_SYSTEM_ROOT "$sysroot" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define TARGET_SYSTEM_ROOT_RELOCATABLE $sysroot_relocatable +_ACEOF + + + +installed_linker=ld.gold +# Check whether --enable-gold was given. +if test "${enable_gold+set}" = set; then : + enableval=$enable_gold; case "${enableval}" in + default) + install_as_default=yes + ;; + yes) + if test x${enable_ld} = xno; then + install_as_default=yes + fi + ;; + esac +else + install_as_default=no +fi + + + + +# Check whether --enable-threads was given. +if test "${enable_threads+set}" = set; then : + enableval=$enable_threads; case "${enableval}" in + yes | "") threads=yes ;; + no) threads=no ;; + *) threads=yes ;; + esac +else + threads=no +fi + +if test "$threads" = "yes"; then + +$as_echo "#define ENABLE_THREADS 1" >>confdefs.h + +fi + if test "$threads" = "yes"; then + THREADS_TRUE= + THREADS_FALSE='#' +else + THREADS_TRUE='#' + THREADS_FALSE= +fi + + +# Check whether --enable-plugins was given. +if test "${enable_plugins+set}" = set; then : + enableval=$enable_plugins; case "${enableval}" in + yes | "") plugins=yes ;; + no) plugins=no ;; + *) plugins=yes ;; + esac +else + plugins=no +fi + +if test "$plugins" = "yes"; then + +$as_echo "#define ENABLE_PLUGINS 1" >>confdefs.h + +fi + if test "$plugins" = "yes"; then + PLUGINS_TRUE= + PLUGINS_FALSE='#' +else + PLUGINS_TRUE='#' + PLUGINS_FALSE= +fi + + +# Check whether --enable-targets was given. +if test "${enable_targets+set}" = set; then : + enableval=$enable_targets; case "${enableval}" in + yes | "") + as_fn_error "--enable-targets option must specify target names or 'all'" "$LINENO" 5 + ;; + no) + enable_targets= + ;; + *) + enable_targets=$enableval + ;; +esac +else + # For now, enable all targets by default + enable_targets=all + +fi + + +# Canonicalize the enabled targets. +if test -n "$enable_targets"; then + for targ in `echo $enable_targets | sed -e 's/,/ /g'`; do + result=`$ac_config_sub $targ 2>/dev/null` + if test -n "$result"; then + canon_targets="$canon_targets $result" + else + # Permit unrecognized target names, like "all". + canon_targets="$canon_targets $targ" + fi + done +fi + +# See which specific instantiations we need. +targetobjs= +all_targets= +default_machine= +default_size= +default_big_endian= +default_osabi=ELFOSABI_NONE +targ_32_little= +targ_32_big= +targ_64_little= +targ_64_big= +for targ in $target $canon_targets; do + if test "$targ" = "all"; then + targ_32_little=yes + targ_32_big=yes + targ_64_little=yes + targ_64_big=yes + all_targets=yes + else + . ${srcdir}/configure.tgt + + if test "$targ_obj" = "UNKNOWN"; then + as_fn_error "\"unsupported target $targ\"" "$LINENO" 5 + else + targetobjs="$targetobjs ${targ_obj}.\$(OBJEXT)" + if test "$targ_extra_obj" != ""; then + targetobjs="$targetobjs ${targ_extra_obj}.\$(OBJEXT)" + fi + if test "$targ_size" = "32" -o "$targ_extra_size" = "32"; then + if test "$targ_big_endian" = "true" \ + -o "$targ_extra_big_endian" = "true"; then + targ_32_big=yes + fi + if test "$targ_big_endian" = "false" \ + -o "$targ_extra_big_endian" = "false"; then + targ_32_little=yes + fi + fi + if test "$targ_size" = "64" -o "$targ_extra_size" = "64"; then + if test "$targ_big_endian" = "true" \ + -o "$targ_extra_big_endian" = "true"; then + targ_64_big=yes + fi + if test "$targ_big_endian" = "false" \ + -o "$targ_extra_big_endian" = "false"; then + targ_64_little=yes + fi + fi + + if test "$target" = "$targ"; then + default_machine=$targ_machine + default_size=$targ_size + default_big_endian=$targ_big_endian + default_osabi=$targ_osabi + + if test "$targ_obj" = "arm"; then + DEFAULT_TARGET_ARM_TRUE= + DEFAULT_TARGET_ARM_FALSE='#' +else + DEFAULT_TARGET_ARM_TRUE='#' + DEFAULT_TARGET_ARM_FALSE= +fi + + if test "$targ_obj" = "i386"; then + DEFAULT_TARGET_I386_TRUE= + DEFAULT_TARGET_I386_FALSE='#' +else + DEFAULT_TARGET_I386_TRUE='#' + DEFAULT_TARGET_I386_FALSE= +fi + + if test "$targ_obj" = "powerpc"; then + DEFAULT_TARGET_POWERPC_TRUE= + DEFAULT_TARGET_POWERPC_FALSE='#' +else + DEFAULT_TARGET_POWERPC_TRUE='#' + DEFAULT_TARGET_POWERPC_FALSE= +fi + + if test "$targ_obj" = "sparc"; then + DEFAULT_TARGET_SPARC_TRUE= + DEFAULT_TARGET_SPARC_FALSE='#' +else + DEFAULT_TARGET_SPARC_TRUE='#' + DEFAULT_TARGET_SPARC_FALSE= +fi + + if test "$targ_obj" = "x86_64"; then + DEFAULT_TARGET_X86_64_TRUE= + DEFAULT_TARGET_X86_64_FALSE='#' +else + DEFAULT_TARGET_X86_64_TRUE='#' + DEFAULT_TARGET_X86_64_FALSE= +fi + + if test "$targ_obj" = "tilegx"; then + DEFAULT_TARGET_TILEGX_TRUE= + DEFAULT_TARGET_TILEGX_FALSE='#' +else + DEFAULT_TARGET_TILEGX_TRUE='#' + DEFAULT_TARGET_TILEGX_FALSE= +fi + + DEFAULT_TARGET=${targ_obj} + + fi + fi + fi +done + +# Remove any duplicates. +to="" +for t in $targetobjs; do + case " $to " in + *" $t "*) ;; + *) to="$to $t" ;; + esac +done +targetobjs=$to + +if test -n "$targ_32_little"; then + +$as_echo "#define HAVE_TARGET_32_LITTLE 1" >>confdefs.h + +fi +if test -n "$targ_32_big"; then + +$as_echo "#define HAVE_TARGET_32_BIG 1" >>confdefs.h + +fi +if test -n "$targ_64_little"; then + +$as_echo "#define HAVE_TARGET_64_LITTLE 1" >>confdefs.h + +fi +if test -n "$targ_64_big"; then + +$as_echo "#define HAVE_TARGET_64_BIG 1" >>confdefs.h + +fi + +if test -n "$all_targets"; then + TARGETOBJS='$(ALL_TARGETOBJS)' +else + TARGETOBJS="$targetobjs" +fi + + + +cat >>confdefs.h <<_ACEOF +#define GOLD_DEFAULT_MACHINE $default_machine +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define GOLD_DEFAULT_SIZE $default_size +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define GOLD_DEFAULT_BIG_ENDIAN $default_big_endian +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define GOLD_DEFAULT_OSABI $default_osabi +_ACEOF + + + +# Check whether --with-lib-path was given. +if test "${with_lib_path+set}" = set; then : + withval=$with_lib_path; case "$withval" in + yes) LIB_PATH='"/lib:/usr/lib"' ;; + no) LIB_PATH='""' ;; + *) LIB_PATH='"'"$withval"'"' ;; + esac +else + LIB_PATH='"::DEFAULT::"' +fi + + +cat >>confdefs.h <<_ACEOF +#define LIB_PATH $LIB_PATH +_ACEOF + +if test "x$target_alias" = "x" -o "x$host_alias" = "x$target_alias"; then + +$as_echo "#define NATIVE_LINKER 1" >>confdefs.h + +fi + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}nm", so it can be a program name with args. +set dummy ${ac_tool_prefix}nm; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_NM+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$NM"; then + ac_cv_prog_NM="$NM" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_NM="${ac_tool_prefix}nm" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +NM=$ac_cv_prog_NM +if test -n "$NM"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NM" >&5 +$as_echo "$NM" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_NM"; then + ac_ct_NM=$NM + # Extract the first word of "nm", so it can be a program name with args. +set dummy nm; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_NM+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_NM"; then + ac_cv_prog_ac_ct_NM="$ac_ct_NM" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_NM="nm" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_NM=$ac_cv_prog_ac_ct_NM +if test -n "$ac_ct_NM"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NM" >&5 +$as_echo "$ac_ct_NM" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_NM" = x; then + NM="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + NM=$ac_ct_NM + fi +else + NM="$ac_cv_prog_NM" +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "no acceptable C compiler found in \$PATH +See \`config.log' for more details." "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + rm -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out conftest.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +if test -z "$ac_file"; then : + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ as_fn_set_status 77 +as_fn_error "C compiler cannot create executables +See \`config.log' for more details." "$LINENO" 5; }; } +fi +ac_exeext=$ac_cv_exeext + +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out conftest.out +ac_clean_files=$ac_clean_files_save +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." "$LINENO" 5; } +fi +rm -f conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if test "${ac_cv_objext+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "cannot compute suffix of object files: cannot compile +See \`config.log' for more details." "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if test "${ac_cv_c_compiler_gnu+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if test "${ac_cv_prog_cc_g+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if test "${ac_cv_prog_cc_c89+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 +$as_echo_n "checking for style of include used by $am_make... " >&6; } +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from `make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 +$as_echo "$_am_result" >&6; } +rm -f confinc confmf + +# Check whether --enable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then : + enableval=$enable_dependency_tracking; +fi + +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi + if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + +depcc="$CC" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +$as_echo "$CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 +$as_echo "$ac_ct_CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + rm -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 +$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } +if test "${ac_cv_cxx_compiler_gnu+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 +$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GXX=yes +else + GXX= +fi +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 +$as_echo_n "checking whether $CXX accepts -g... " >&6; } +if test "${ac_cv_prog_cxx_g+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +else + CXXFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +else + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 +$as_echo "$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$CXX" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CXX_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CXX_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CXX_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } +CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then + am__fastdepCXX_TRUE= + am__fastdepCXX_FALSE='#' +else + am__fastdepCXX_TRUE='#' + am__fastdepCXX_FALSE= +fi + + +for ac_prog in 'bison -y' byacc +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_YACC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$YACC"; then + ac_cv_prog_YACC="$YACC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_YACC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +YACC=$ac_cv_prog_YACC +if test -n "$YACC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5 +$as_echo "$YACC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$YACC" && break +done +test -n "$YACC" || YACC="yacc" + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_RANLIB+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5 +$as_echo "$RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5 +$as_echo "$ac_ct_RANLIB" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5 +$as_echo_n "checking whether ln -s works... " >&6; } +LN_S=$as_ln_s +if test "$LN_S" = "ln -s"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5 +$as_echo "no, using $LN_S" >&6; } +fi + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 +$as_echo_n "checking how to run the C preprocessor... " >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 +$as_echo "$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_c_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." "$LINENO" 5; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 +$as_echo_n "checking for grep that handles long lines and -e... " >&6; } +if test "${ac_cv_path_GREP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$GREP"; then + ac_path_GREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue +# Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_GREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_GREP"; then + as_fn_error "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_GREP=$GREP +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 +$as_echo "$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 +$as_echo_n "checking for egrep... " >&6; } +if test "${ac_cv_path_EGREP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + if test -z "$EGREP"; then + ac_path_EGREP_found=false + # Loop through the user's path and test for each of PROGNAME-LIST + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue +# Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + $as_echo_n 0123456789 >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + $as_echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + as_fn_arith $ac_count + 1 && ac_count=$as_val + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + $ac_path_EGREP_found && break 3 + done + done + done +IFS=$as_save_IFS + if test -z "$ac_cv_path_EGREP"; then + as_fn_error "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 + fi +else + ac_cv_path_EGREP=$EGREP +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 +$as_echo "$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 +$as_echo_n "checking for ANSI C header files... " >&6; } +if test "${ac_cv_header_stdc+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_header_stdc=yes +else + ac_cv_header_stdc=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then : + +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then : + : +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + +fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 +$as_echo "$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +$as_echo "#define STDC_HEADERS 1" >>confdefs.h + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default +" +eval as_val=\$$as_ac_Header + if test "x$as_val" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default" +if test "x$ac_cv_header_minix_config_h" = x""yes; then : + MINIX=yes +else + MINIX= +fi + + + if test "$MINIX" = yes; then + +$as_echo "#define _POSIX_SOURCE 1" >>confdefs.h + + +$as_echo "#define _POSIX_1_SOURCE 2" >>confdefs.h + + +$as_echo "#define _MINIX 1" >>confdefs.h + + fi + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5 +$as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; } +if test "${ac_cv_safe_to_define___extensions__+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +# define __EXTENSIONS__ 1 + $ac_includes_default +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_safe_to_define___extensions__=yes +else + ac_cv_safe_to_define___extensions__=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5 +$as_echo "$ac_cv_safe_to_define___extensions__" >&6; } + test $ac_cv_safe_to_define___extensions__ = yes && + $as_echo "#define __EXTENSIONS__ 1" >>confdefs.h + + $as_echo "#define _ALL_SOURCE 1" >>confdefs.h + + $as_echo "#define _GNU_SOURCE 1" >>confdefs.h + + $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h + + $as_echo "#define _TANDEM_SOURCE 1" >>confdefs.h + + + + +# If we haven't got the data from the intl directory, +# assume NLS is disabled. +USE_NLS=no +LIBINTL= +LIBINTL_DEP= +INCINTL= +XGETTEXT= +GMSGFMT= +POSUB= + +if test -f ../intl/config.intl; then + . ../intl/config.intl +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether NLS is requested" >&5 +$as_echo_n "checking whether NLS is requested... " >&6; } +if test x"$USE_NLS" != xyes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + +$as_echo "#define ENABLE_NLS 1" >>confdefs.h + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for catalogs to be installed" >&5 +$as_echo_n "checking for catalogs to be installed... " >&6; } + # Look for .po and .gmo files in the source directory. + CATALOGS= + XLINGUAS= + for cat in $srcdir/po/*.gmo $srcdir/po/*.po; do + # If there aren't any .gmo files the shell will give us the + # literal string "../path/to/srcdir/po/*.gmo" which has to be + # weeded out. + case "$cat" in *\**) + continue;; + esac + # The quadruple backslash is collapsed to a double backslash + # by the backticks, then collapsed again by the double quotes, + # leaving us with one backslash in the sed expression (right + # before the dot that mustn't act as a wildcard). + cat=`echo $cat | sed -e "s!$srcdir/po/!!" -e "s!\\\\.po!.gmo!"` + lang=`echo $cat | sed -e "s!\\\\.gmo!!"` + # The user is allowed to set LINGUAS to a list of languages to + # install catalogs for. If it's empty that means "all of them." + if test "x$LINGUAS" = x; then + CATALOGS="$CATALOGS $cat" + XLINGUAS="$XLINGUAS $lang" + else + case "$LINGUAS" in *$lang*) + CATALOGS="$CATALOGS $cat" + XLINGUAS="$XLINGUAS $lang" + ;; + esac + fi + done + LINGUAS="$XLINGUAS" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LINGUAS" >&5 +$as_echo "$LINGUAS" >&6; } + + + DATADIRNAME=share + + INSTOBJEXT=.mo + + GENCAT=gencat + + CATOBJEXT=.gmo + +fi + + MKINSTALLDIRS= + if test -n "$ac_aux_dir"; then + case "$ac_aux_dir" in + /*) MKINSTALLDIRS="$ac_aux_dir/mkinstalldirs" ;; + *) MKINSTALLDIRS="\$(top_builddir)/$ac_aux_dir/mkinstalldirs" ;; + esac + fi + if test -z "$MKINSTALLDIRS"; then + MKINSTALLDIRS="\$(top_srcdir)/mkinstalldirs" + fi + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether NLS is requested" >&5 +$as_echo_n "checking whether NLS is requested... " >&6; } + # Check whether --enable-nls was given. +if test "${enable_nls+set}" = set; then : + enableval=$enable_nls; USE_NLS=$enableval +else + USE_NLS=yes +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_NLS" >&5 +$as_echo "$USE_NLS" >&6; } + + + + + + +# Prepare PATH_SEPARATOR. +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Find out how to test for executable files. Don't use a zero-byte file, +# as systems may use methods other than mode bits to determine executability. +cat >conf$$.file <<_ASEOF +#! /bin/sh +exit 0 +_ASEOF +chmod +x conf$$.file +if test -x conf$$.file >/dev/null 2>&1; then + ac_executable_p="test -x" +else + ac_executable_p="test -f" +fi +rm -f conf$$.file + +# Extract the first word of "msgfmt", so it can be a program name with args. +set dummy msgfmt; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_path_MSGFMT+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case "$MSGFMT" in + [\\/]* | ?:[\\/]*) + ac_cv_path_MSGFMT="$MSGFMT" # Let the user override the test with a path. + ;; + *) + ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$ac_save_IFS" + test -z "$ac_dir" && ac_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then + if $ac_dir/$ac_word --statistics /dev/null >/dev/null 2>&1 && + (if $ac_dir/$ac_word --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then + ac_cv_path_MSGFMT="$ac_dir/$ac_word$ac_exec_ext" + break 2 + fi + fi + done + done + IFS="$ac_save_IFS" + test -z "$ac_cv_path_MSGFMT" && ac_cv_path_MSGFMT=":" + ;; +esac +fi +MSGFMT="$ac_cv_path_MSGFMT" +if test "$MSGFMT" != ":"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MSGFMT" >&5 +$as_echo "$MSGFMT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + # Extract the first word of "gmsgfmt", so it can be a program name with args. +set dummy gmsgfmt; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_path_GMSGFMT+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case $GMSGFMT in + [\\/]* | ?:[\\/]*) + ac_cv_path_GMSGFMT="$GMSGFMT" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_GMSGFMT="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_GMSGFMT" && ac_cv_path_GMSGFMT="$MSGFMT" + ;; +esac +fi +GMSGFMT=$ac_cv_path_GMSGFMT +if test -n "$GMSGFMT"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GMSGFMT" >&5 +$as_echo "$GMSGFMT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + + +# Prepare PATH_SEPARATOR. +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Find out how to test for executable files. Don't use a zero-byte file, +# as systems may use methods other than mode bits to determine executability. +cat >conf$$.file <<_ASEOF +#! /bin/sh +exit 0 +_ASEOF +chmod +x conf$$.file +if test -x conf$$.file >/dev/null 2>&1; then + ac_executable_p="test -x" +else + ac_executable_p="test -f" +fi +rm -f conf$$.file + +# Extract the first word of "xgettext", so it can be a program name with args. +set dummy xgettext; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_path_XGETTEXT+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case "$XGETTEXT" in + [\\/]* | ?:[\\/]*) + ac_cv_path_XGETTEXT="$XGETTEXT" # Let the user override the test with a path. + ;; + *) + ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$ac_save_IFS" + test -z "$ac_dir" && ac_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then + if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >/dev/null 2>&1 && + (if $ac_dir/$ac_word --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then + ac_cv_path_XGETTEXT="$ac_dir/$ac_word$ac_exec_ext" + break 2 + fi + fi + done + done + IFS="$ac_save_IFS" + test -z "$ac_cv_path_XGETTEXT" && ac_cv_path_XGETTEXT=":" + ;; +esac +fi +XGETTEXT="$ac_cv_path_XGETTEXT" +if test "$XGETTEXT" != ":"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $XGETTEXT" >&5 +$as_echo "$XGETTEXT" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + rm -f messages.po + + +# Prepare PATH_SEPARATOR. +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Find out how to test for executable files. Don't use a zero-byte file, +# as systems may use methods other than mode bits to determine executability. +cat >conf$$.file <<_ASEOF +#! /bin/sh +exit 0 +_ASEOF +chmod +x conf$$.file +if test -x conf$$.file >/dev/null 2>&1; then + ac_executable_p="test -x" +else + ac_executable_p="test -f" +fi +rm -f conf$$.file + +# Extract the first word of "msgmerge", so it can be a program name with args. +set dummy msgmerge; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_path_MSGMERGE+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case "$MSGMERGE" in + [\\/]* | ?:[\\/]*) + ac_cv_path_MSGMERGE="$MSGMERGE" # Let the user override the test with a path. + ;; + *) + ac_save_IFS="$IFS"; IFS=$PATH_SEPARATOR + for ac_dir in $PATH; do + IFS="$ac_save_IFS" + test -z "$ac_dir" && ac_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $ac_executable_p "$ac_dir/$ac_word$ac_exec_ext"; then + if $ac_dir/$ac_word --update -q /dev/null /dev/null >/dev/null 2>&1; then + ac_cv_path_MSGMERGE="$ac_dir/$ac_word$ac_exec_ext" + break 2 + fi + fi + done + done + IFS="$ac_save_IFS" + test -z "$ac_cv_path_MSGMERGE" && ac_cv_path_MSGMERGE=":" + ;; +esac +fi +MSGMERGE="$ac_cv_path_MSGMERGE" +if test "$MSGMERGE" != ":"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MSGMERGE" >&5 +$as_echo "$MSGMERGE" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + if test "$GMSGFMT" != ":"; then + if $GMSGFMT --statistics /dev/null >/dev/null 2>&1 && + (if $GMSGFMT --statistics /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then + : ; + else + GMSGFMT=`echo "$GMSGFMT" | sed -e 's,^.*/,,'` + { $as_echo "$as_me:${as_lineno-$LINENO}: result: found $GMSGFMT program is not GNU msgfmt; ignore it" >&5 +$as_echo "found $GMSGFMT program is not GNU msgfmt; ignore it" >&6; } + GMSGFMT=":" + fi + fi + + if test "$XGETTEXT" != ":"; then + if $XGETTEXT --omit-header --copyright-holder= --msgid-bugs-address= /dev/null >/dev/null 2>&1 && + (if $XGETTEXT --omit-header --copyright-holder= --msgid-bugs-address= /dev/null 2>&1 >/dev/null | grep usage >/dev/null; then exit 1; else exit 0; fi); then + : ; + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: found xgettext program is not GNU xgettext; ignore it" >&5 +$as_echo "found xgettext program is not GNU xgettext; ignore it" >&6; } + XGETTEXT=":" + fi + rm -f messages.po + fi + + ac_config_commands="$ac_config_commands default-1" + + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether byte ordering is bigendian" >&5 +$as_echo_n "checking whether byte ordering is bigendian... " >&6; } +if test "${ac_cv_c_bigendian+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_c_bigendian=unknown + # See if we're dealing with a universal compiler. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifndef __APPLE_CC__ + not a universal capable compiler + #endif + typedef int dummy; + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + + # Check for potential -arch flags. It is not universal unless + # there are at least two -arch flags with different values. + ac_arch= + ac_prev= + for ac_word in $CC $CFLAGS $CPPFLAGS $LDFLAGS; do + if test -n "$ac_prev"; then + case $ac_word in + i?86 | x86_64 | ppc | ppc64) + if test -z "$ac_arch" || test "$ac_arch" = "$ac_word"; then + ac_arch=$ac_word + else + ac_cv_c_bigendian=universal + break + fi + ;; + esac + ac_prev= + elif test "x$ac_word" = "x-arch"; then + ac_prev=arch + fi + done +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + if test $ac_cv_c_bigendian = unknown; then + # See if sys/param.h defines the BYTE_ORDER macro. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + +int +main () +{ +#if ! (defined BYTE_ORDER && defined BIG_ENDIAN \ + && defined LITTLE_ENDIAN && BYTE_ORDER && BIG_ENDIAN \ + && LITTLE_ENDIAN) + bogus endian macros + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + # It does; now see whether it defined to BIG_ENDIAN or not. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + #include + +int +main () +{ +#if BYTE_ORDER != BIG_ENDIAN + not big endian + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_bigendian=yes +else + ac_cv_c_bigendian=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + if test $ac_cv_c_bigendian = unknown; then + # See if defines _LITTLE_ENDIAN or _BIG_ENDIAN (e.g., Solaris). + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +int +main () +{ +#if ! (defined _LITTLE_ENDIAN || defined _BIG_ENDIAN) + bogus endian macros + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + # It does; now see whether it defined to _BIG_ENDIAN or not. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include + +int +main () +{ +#ifndef _BIG_ENDIAN + not big endian + #endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_c_bigendian=yes +else + ac_cv_c_bigendian=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + if test $ac_cv_c_bigendian = unknown; then + # Compile a test program. + if test "$cross_compiling" = yes; then : + # Try to guess by grepping values from an object file. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +short int ascii_mm[] = + { 0x4249, 0x4765, 0x6E44, 0x6961, 0x6E53, 0x7953, 0 }; + short int ascii_ii[] = + { 0x694C, 0x5454, 0x656C, 0x6E45, 0x6944, 0x6E61, 0 }; + int use_ascii (int i) { + return ascii_mm[i] + ascii_ii[i]; + } + short int ebcdic_ii[] = + { 0x89D3, 0xE3E3, 0x8593, 0x95C5, 0x89C4, 0x9581, 0 }; + short int ebcdic_mm[] = + { 0xC2C9, 0xC785, 0x95C4, 0x8981, 0x95E2, 0xA8E2, 0 }; + int use_ebcdic (int i) { + return ebcdic_mm[i] + ebcdic_ii[i]; + } + extern int foo; + +int +main () +{ +return use_ascii (foo) == use_ebcdic (foo); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + if grep BIGenDianSyS conftest.$ac_objext >/dev/null; then + ac_cv_c_bigendian=yes + fi + if grep LiTTleEnDian conftest.$ac_objext >/dev/null ; then + if test "$ac_cv_c_bigendian" = unknown; then + ac_cv_c_bigendian=no + else + # finding both strings is unlikely to happen, but who knows? + ac_cv_c_bigendian=unknown + fi + fi +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +$ac_includes_default +int +main () +{ + + /* Are we little or big endian? From Harbison&Steele. */ + union + { + long int l; + char c[sizeof (long int)]; + } u; + u.l = 1; + return u.c[sizeof (long int) - 1] == 1; + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + ac_cv_c_bigendian=no +else + ac_cv_c_bigendian=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_bigendian" >&5 +$as_echo "$ac_cv_c_bigendian" >&6; } + case $ac_cv_c_bigendian in #( + yes) + $as_echo "#define WORDS_BIGENDIAN 1" >>confdefs.h +;; #( + no) + ;; #( + universal) + +$as_echo "#define AC_APPLE_UNIVERSAL_BUILD 1" >>confdefs.h + + ;; #( + *) + as_fn_error "unknown endianness + presetting ac_cv_c_bigendian=no (or yes) will help" "$LINENO" 5 ;; + esac + + + + + if test "x$target_alias" = "x" -o "x$host_alias" = "x$target_alias"; then + NATIVE_LINKER_TRUE= + NATIVE_LINKER_FALSE='#' +else + NATIVE_LINKER_TRUE='#' + NATIVE_LINKER_FALSE= +fi + + if test "$GCC" = yes; then + GCC_TRUE= + GCC_FALSE='#' +else + GCC_TRUE='#' + GCC_FALSE= +fi + + + if test "x$target_alias" = "x" -o "x$host_alias" = "x$target_alias" -o "x$host_alias" = "x$build_alias"; then + NATIVE_OR_CROSS_LINKER_TRUE= + NATIVE_OR_CROSS_LINKER_FALSE='#' +else + NATIVE_OR_CROSS_LINKER_TRUE='#' + NATIVE_OR_CROSS_LINKER_FALSE= +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether static linking works" >&5 +$as_echo_n "checking whether static linking works... " >&6; } +if test "${gold_cv_lib_static+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + LDFLAGS_hold=$LDFLAGS +LDFLAGS="$LDFLAGS -static" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +void f() { } +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + gold_cv_lib_static=yes +else + gold_cv_lib_static=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LDFLAGS=$LDFLAGS_hold +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gold_cv_lib_static" >&5 +$as_echo "$gold_cv_lib_static" >&6; } + if test "$gold_cv_lib_static" = "yes"; then + HAVE_STATIC_TRUE= + HAVE_STATIC_FALSE='#' +else + HAVE_STATIC_TRUE='#' + HAVE_STATIC_FALSE= +fi + + + if + case $target_cpu in + powerpc*) false;; + x86_64) false;; + sparc64) false;; + *) true;; + esac; then + FN_PTRS_IN_SO_WITHOUT_PIC_TRUE= + FN_PTRS_IN_SO_WITHOUT_PIC_FALSE='#' +else + FN_PTRS_IN_SO_WITHOUT_PIC_TRUE='#' + FN_PTRS_IN_SO_WITHOUT_PIC_FALSE= +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for gcc >= 4.1" >&5 +$as_echo_n "checking for gcc >= 4.1... " >&6; } +if test "${gold_cv_prog_gcc41+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#if !defined __GNUC__ +error +#elif __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 1) +error +#endif + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gold_cv_prog_gcc41=yes +else + gold_cv_prog_gcc41=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gold_cv_prog_gcc41" >&5 +$as_echo "$gold_cv_prog_gcc41" >&6; } + +save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -mcmodel=medium" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int i; +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + have_mcmodel_medium=yes +else + have_mcmodel_medium=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +CFLAGS="$save_CFLAGS" + if test "$target_cpu" = "x86_64" -a "$have_mcmodel_medium" = "yes" -a "$gold_cv_prog_gcc41" = "yes"; then + MCMODEL_MEDIUM_TRUE= + MCMODEL_MEDIUM_FALSE='#' +else + MCMODEL_MEDIUM_TRUE='#' + MCMODEL_MEDIUM_FALSE= +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC supports -fmerge-constants" >&5 +$as_echo_n "checking whether $CC supports -fmerge-constants... " >&6; } +if test "${gold_cv_merge_constants+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + +save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -fmerge-constants" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +const char *s = "foo"; +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + have_merge_constants=yes +else + have_merge_constants=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +CFLAGS="$save_CFLAGS" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gold_cv_merge_constants" >&5 +$as_echo "$gold_cv_merge_constants" >&6; } + +if test "$gold_cv_merge_constants" = yes; then : + MERGE_CONSTANTS_FLAG=-fmerge-constants +else + MERGE_CONSTANTS_FLAG= +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for thread support" >&5 +$as_echo_n "checking for thread support... " >&6; } +if test "${gold_cv_c_thread+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +__thread int i = 1; +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gold_cv_c_thread=yes +else + gold_cv_c_thread=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gold_cv_c_thread" >&5 +$as_echo "$gold_cv_c_thread" >&6; } + + if test "$gold_cv_c_thread" = "yes"; then + TLS_TRUE= + TLS_FALSE='#' +else + TLS_TRUE='#' + TLS_FALSE= +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for glibc >= 2.4" >&5 +$as_echo_n "checking for glibc >= 2.4... " >&6; } +if test "${gold_cv_lib_glibc24+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#if !defined __GLIBC__ +error +#elif __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 4) +error +#endif + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gold_cv_lib_glibc24=yes +else + gold_cv_lib_glibc24=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gold_cv_lib_glibc24" >&5 +$as_echo "$gold_cv_lib_glibc24" >&6; } + + if test "$gold_cv_lib_glibc24" = "yes"; then + STATIC_TLS_TRUE= + STATIC_TLS_FALSE='#' +else + STATIC_TLS_TRUE='#' + STATIC_TLS_FALSE= +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for omp support" >&5 +$as_echo_n "checking for omp support... " >&6; } +if test "${gold_cv_c_threadprivate+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -fopenmp" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +int i; +#pragma omp threadprivate (i) + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gold_cv_c_threadprivate=yes +else + gold_cv_c_threadprivate=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +CFLAGS="$save_CFLAGS" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gold_cv_c_threadprivate" >&5 +$as_echo "$gold_cv_c_threadprivate" >&6; } +if test "$gold_cv_c_threadprivate" = "yes"; then + +$as_echo "#define HAVE_OMP_SUPPORT 1" >>confdefs.h + +fi + if test "$gold_cv_c_threadprivate" = "yes"; then + OMP_SUPPORT_TRUE= + OMP_SUPPORT_FALSE='#' +else + OMP_SUPPORT_TRUE='#' + OMP_SUPPORT_FALSE= +fi + + +save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -Werror -fpic -mtls-dialect=gnu2" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +__thread int i; +void foo (void) +{ + i = 10; +} + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + have_tls_gnu2=yes +else + have_tls_gnu2=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +CFLAGS="$save_CFLAGS" + if test "$have_tls_gnu2" = "yes"; then + TLS_GNU2_DIALECT_TRUE= + TLS_GNU2_DIALECT_FALSE='#' +else + TLS_GNU2_DIALECT_TRUE='#' + TLS_GNU2_DIALECT_FALSE= +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for glibc >= 2.9" >&5 +$as_echo_n "checking for glibc >= 2.9... " >&6; } +if test "${gold_cv_lib_glibc29+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#if !defined __GLIBC__ +error +#elif __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 9) +error +#endif + +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gold_cv_lib_glibc29=yes +else + gold_cv_lib_glibc29=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gold_cv_lib_glibc29" >&5 +$as_echo "$gold_cv_lib_glibc29" >&6; } + + if test "$gold_cv_lib_glibc29" = "yes"; then + TLS_DESCRIPTORS_TRUE= + TLS_DESCRIPTORS_FALSE='#' +else + TLS_DESCRIPTORS_TRUE='#' + TLS_DESCRIPTORS_FALSE= +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for -frandom-seed support" >&5 +$as_echo_n "checking for -frandom-seed support... " >&6; } +if test "${gold_cv_c_random_seed+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -frandom-seed=foo" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int i; +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + gold_cv_c_random_seed=yes +else + gold_cv_c_random_seed=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +CFLAGS="$save_CFLAGS" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gold_cv_c_random_seed" >&5 +$as_echo "$gold_cv_c_random_seed" >&6; } +if test "$gold_cv_c_random_seed" = "yes"; then + # In Makefile, '$@' will be expanded to be the name of the file + # being built, providing a unique seed for each file. + RANDOM_SEED_CFLAGS=-frandom-seed=\$@ +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for glibc ifunc support" >&5 +$as_echo_n "checking for glibc ifunc support... " >&6; } +if test "${gold_cv_lib_glibc_ifunc+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + save_LDFLAGS="$LDFLAGS" +LDFLAGS="$LDFLAGS -static" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#if !defined __GLIBC__ +error +#elif __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 11) +error +#endif +void func (void) { } +void invoke (void); +__asm__(".type invoke, %gnu_indirect_function"); +typedef void (*funcptr) (void); +funcptr dispatch (void) __asm__ ("invoke"); +funcptr dispatch (void) { return &func; } +int +main () +{ +invoke(); + ; + return 0; +} + +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + +if ${NM} conftest$EXEEXT | grep "__rela\?_iplt_start" >/dev/null 2>&1; then + gold_cv_lib_glibc_ifunc=both +else + gold_cv_lib_glibc_ifunc=dyn +fi +else + gold_cv_lib_glibc_ifunc=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LDFLAGS="$save_LDFLAGS" +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gold_cv_lib_glibc_ifunc" >&5 +$as_echo "$gold_cv_lib_glibc_ifunc" >&6; } + + if test "$gold_cv_lib_glibc_ifunc" != "no"; then + IFUNC_TRUE= + IFUNC_FALSE='#' +else + IFUNC_TRUE='#' + IFUNC_FALSE= +fi + + if test "$gold_cv_lib_glibc_ifunc" = "both"; then + IFUNC_STATIC_TRUE= + IFUNC_STATIC_FALSE='#' +else + IFUNC_STATIC_TRUE='#' + IFUNC_STATIC_FALSE= +fi + + + +GCC_WARN_CFLAGS="-W -Wall -Wstrict-prototypes -Wmissing-prototypes" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +__GNUC__ +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "^[0-3]$" >/dev/null 2>&1; then : + +else + GCC_WARN_CFLAGS="$GCC_WARN_CFLAGS -Wshadow" +fi +rm -f conftest* + + +# Check whether --enable-werror was given. +if test "${enable_werror+set}" = set; then : + enableval=$enable_werror; case "${enableval}" in + yes | y) ERROR_ON_WARNING="yes" ;; + no | n) ERROR_ON_WARNING="no" ;; + *) as_fn_error "bad value ${enableval} for --enable-werror" "$LINENO" 5 ;; + esac +fi + + +# Disable -Wformat by default when using gcc on mingw +case "${host}" in + *-*-mingw32*) + if test "${GCC}" = yes -a -z "${ERROR_ON_WARNING}" ; then + GCC_WARN_CFLAGS="$GCC_WARN_CFLAGS -Wno-format" + fi + ;; + *) ;; +esac + +# Enable -Werror by default when using gcc +if test "${GCC}" = yes -a -z "${ERROR_ON_WARNING}" ; then + ERROR_ON_WARNING=yes +fi + +NO_WERROR= +if test "${ERROR_ON_WARNING}" = yes ; then + GCC_WARN_CFLAGS="$GCC_WARN_CFLAGS -Werror" + NO_WERROR="-Wno-error" +fi + +if test "${GCC}" = yes ; then + WARN_CFLAGS="${GCC_WARN_CFLAGS}" +fi + +# Check whether --enable-build-warnings was given. +if test "${enable_build_warnings+set}" = set; then : + enableval=$enable_build_warnings; case "${enableval}" in + yes) WARN_CFLAGS="${GCC_WARN_CFLAGS}";; + no) if test "${GCC}" = yes ; then + WARN_CFLAGS="-w" + fi;; + ,*) t=`echo "${enableval}" | sed -e "s/,/ /g"` + WARN_CFLAGS="${GCC_WARN_CFLAGS} ${t}";; + *,) t=`echo "${enableval}" | sed -e "s/,/ /g"` + WARN_CFLAGS="${t} ${GCC_WARN_CFLAGS}";; + *) WARN_CFLAGS=`echo "${enableval}" | sed -e "s/,/ /g"`;; +esac +fi + + +if test x"$silent" != x"yes" && test x"$WARN_CFLAGS" != x""; then + echo "Setting warning flags = $WARN_CFLAGS" 6>&1 +fi + + + + + +WARN_CXXFLAGS=`echo ${WARN_CFLAGS} | sed -e 's/-Wstrict-prototypes//' -e 's/-Wmissing-prototypes//' -e 's/-Wshadow//'` + + + +# Check whether --with-gold-ldflags was given. +if test "${with_gold_ldflags+set}" = set; then : + withval=$with_gold_ldflags; if test "$withval" = "no" -o "$withval" = "yes"; then + GOLD_LDFLAGS= + else + GOLD_LDFLAGS=$withval + fi +else + GOLD_LDFLAGS= +fi + + + + +# Check whether --with-gold-ldadd was given. +if test "${with_gold_ldadd+set}" = set; then : + withval=$with_gold_ldadd; if test "$withval" = "no" -o "$withval" = "yes"; then + GOLD_LDADD= + else + GOLD_LDADD=$withval + fi +else + GOLD_LDADD= +fi + + + +LFS_CFLAGS="-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64" + + +for ac_header in sys/mman.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "sys/mman.h" "ac_cv_header_sys_mman_h" "$ac_includes_default" +if test "x$ac_cv_header_sys_mman_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SYS_MMAN_H 1 +_ACEOF + +fi + +done + +for ac_func in chsize mmap +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +eval as_val=\$$as_ac_var + if test "x$as_val" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +for ac_func in pread ftruncate ffsll +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +eval as_val=\$$as_ac_var + if test "x$as_val" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +else + case " $LIBOBJS " in + *" $ac_func.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS $ac_func.$ac_objext" + ;; +esac + +fi +done + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking mremap with MREMAP_MAYMOVE" >&5 +$as_echo_n "checking mremap with MREMAP_MAYMOVE... " >&6; } +if test "${gold_cv_lib_mremap_maymove+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#include +void f() { mremap (0, 0, 0, MREMAP_MAYMOVE); } + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + gold_cv_lib_mremap_maymove=yes +else + gold_cv_lib_mremap_maymove=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gold_cv_lib_mremap_maymove" >&5 +$as_echo "$gold_cv_lib_mremap_maymove" >&6; } +if test "$gold_cv_lib_mremap_maymove" = "yes"; then + +$as_echo "#define HAVE_MREMAP 1" >>confdefs.h + +else + case " $LIBOBJS " in + *" mremap.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS mremap.$ac_objext" + ;; +esac + +fi + +# Link in zlib if we can. This allows us to write compressed sections. + + # See if the user specified whether he wants zlib support or not. + +# Check whether --with-zlib was given. +if test "${with_zlib+set}" = set; then : + withval=$with_zlib; +else + with_zlib=auto +fi + + + if test "$with_zlib" != "no"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing zlibVersion" >&5 +$as_echo_n "checking for library containing zlibVersion... " >&6; } +if test "${ac_cv_search_zlibVersion+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_func_search_save_LIBS=$LIBS +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char zlibVersion (); +int +main () +{ +return zlibVersion (); + ; + return 0; +} +_ACEOF +for ac_lib in '' z; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + if ac_fn_c_try_link "$LINENO"; then : + ac_cv_search_zlibVersion=$ac_res +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext + if test "${ac_cv_search_zlibVersion+set}" = set; then : + break +fi +done +if test "${ac_cv_search_zlibVersion+set}" = set; then : + +else + ac_cv_search_zlibVersion=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_zlibVersion" >&5 +$as_echo "$ac_cv_search_zlibVersion" >&6; } +ac_res=$ac_cv_search_zlibVersion +if test "$ac_res" != no; then : + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + for ac_header in zlib.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "zlib.h" "ac_cv_header_zlib_h" "$ac_includes_default" +if test "x$ac_cv_header_zlib_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_ZLIB_H 1 +_ACEOF + +fi + +done + +fi + + if test "$with_zlib" = "yes" -a "$ac_cv_header_zlib_h" != "yes"; then + as_fn_error "zlib (libz) library was explicitly requested but not found" "$LINENO" 5 + fi + fi + + if test "$ac_cv_header_zlib_h" = "yes"; then + HAVE_ZLIB_TRUE= + HAVE_ZLIB_FALSE='#' +else + HAVE_ZLIB_TRUE='#' + HAVE_ZLIB_FALSE= +fi + + +ac_fn_c_check_decl "$LINENO" "basename" "ac_cv_have_decl_basename" "$ac_includes_default" +if test "x$ac_cv_have_decl_basename" = x""yes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_BASENAME $ac_have_decl +_ACEOF +ac_fn_c_check_decl "$LINENO" "ffs" "ac_cv_have_decl_ffs" "$ac_includes_default" +if test "x$ac_cv_have_decl_ffs" = x""yes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_FFS $ac_have_decl +_ACEOF +ac_fn_c_check_decl "$LINENO" "asprintf" "ac_cv_have_decl_asprintf" "$ac_includes_default" +if test "x$ac_cv_have_decl_asprintf" = x""yes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_ASPRINTF $ac_have_decl +_ACEOF +ac_fn_c_check_decl "$LINENO" "vasprintf" "ac_cv_have_decl_vasprintf" "$ac_includes_default" +if test "x$ac_cv_have_decl_vasprintf" = x""yes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_VASPRINTF $ac_have_decl +_ACEOF +ac_fn_c_check_decl "$LINENO" "snprintf" "ac_cv_have_decl_snprintf" "$ac_includes_default" +if test "x$ac_cv_have_decl_snprintf" = x""yes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_SNPRINTF $ac_have_decl +_ACEOF +ac_fn_c_check_decl "$LINENO" "vsnprintf" "ac_cv_have_decl_vsnprintf" "$ac_includes_default" +if test "x$ac_cv_have_decl_vsnprintf" = x""yes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_VSNPRINTF $ac_have_decl +_ACEOF +ac_fn_c_check_decl "$LINENO" "strverscmp" "ac_cv_have_decl_strverscmp" "$ac_includes_default" +if test "x$ac_cv_have_decl_strverscmp" = x""yes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_STRVERSCMP $ac_have_decl +_ACEOF + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 +$as_echo_n "checking how to run the C++ preprocessor... " >&6; } +if test -z "$CXXCPP"; then + if test "${ac_cv_prog_CXXCPP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + # Double quotes because CXXCPP needs to be expanded + for CXXCPP in "$CXX -E" "/lib/cpp" + do + ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + break +fi + + done + ac_cv_prog_CXXCPP=$CXXCPP + +fi + CXXCPP=$ac_cv_prog_CXXCPP +else + ac_cv_prog_CXXCPP=$CXXCPP +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 +$as_echo "$CXXCPP" >&6; } +ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + +else + # Broken: fails on valid input. +continue +fi +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +_ACEOF +if ac_fn_cxx_try_cpp "$LINENO"; then : + # Broken: success on invalid input. +continue +else + # Passes both tests. +ac_preproc_ok=: +break +fi +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then : + +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details." "$LINENO" 5; } +fi + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + +for ac_header in tr1/unordered_set tr1/unordered_map +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_cxx_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +eval as_val=\$$as_ac_Header + if test "x$as_val" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +for ac_header in ext/hash_map ext/hash_set +do : + as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` +ac_fn_cxx_check_header_mongrel "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default" +eval as_val=\$$as_ac_Header + if test "x$as_val" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +for ac_header in byteswap.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "byteswap.h" "ac_cv_header_byteswap_h" "$ac_includes_default" +if test "x$ac_cv_header_byteswap_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_BYTESWAP_H 1 +_ACEOF + +fi + +done + + +for ac_header in windows.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "windows.h" "ac_cv_header_windows_h" "$ac_includes_default" +if test "x$ac_cv_header_windows_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_WINDOWS_H 1 +_ACEOF + +fi + +done + +for ac_header in dlfcn.h +do : + ac_fn_cxx_check_header_mongrel "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default" +if test "x$ac_cv_header_dlfcn_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_DLFCN_H 1 +_ACEOF + DLOPEN_LIBS="-ldl" +else + DLOPEN_LIBS="" +fi + +done + + + +for ac_func in mallinfo posix_fallocate fallocate readv sysconf times +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_cxx_check_func "$LINENO" "$ac_func" "$as_ac_var" +eval as_val=\$$as_ac_var + if test "x$as_val" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +ac_fn_cxx_check_decl "$LINENO" "basename" "ac_cv_have_decl_basename" "$ac_includes_default" +if test "x$ac_cv_have_decl_basename" = x""yes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_BASENAME $ac_have_decl +_ACEOF +ac_fn_cxx_check_decl "$LINENO" "ffs" "ac_cv_have_decl_ffs" "$ac_includes_default" +if test "x$ac_cv_have_decl_ffs" = x""yes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_FFS $ac_have_decl +_ACEOF +ac_fn_cxx_check_decl "$LINENO" "asprintf" "ac_cv_have_decl_asprintf" "$ac_includes_default" +if test "x$ac_cv_have_decl_asprintf" = x""yes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_ASPRINTF $ac_have_decl +_ACEOF +ac_fn_cxx_check_decl "$LINENO" "vasprintf" "ac_cv_have_decl_vasprintf" "$ac_includes_default" +if test "x$ac_cv_have_decl_vasprintf" = x""yes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_VASPRINTF $ac_have_decl +_ACEOF +ac_fn_cxx_check_decl "$LINENO" "snprintf" "ac_cv_have_decl_snprintf" "$ac_includes_default" +if test "x$ac_cv_have_decl_snprintf" = x""yes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_SNPRINTF $ac_have_decl +_ACEOF +ac_fn_cxx_check_decl "$LINENO" "vsnprintf" "ac_cv_have_decl_vsnprintf" "$ac_includes_default" +if test "x$ac_cv_have_decl_vsnprintf" = x""yes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_VSNPRINTF $ac_have_decl +_ACEOF +ac_fn_cxx_check_decl "$LINENO" "strverscmp" "ac_cv_have_decl_strverscmp" "$ac_includes_default" +if test "x$ac_cv_have_decl_strverscmp" = x""yes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_STRVERSCMP $ac_have_decl +_ACEOF +ac_fn_cxx_check_decl "$LINENO" "strndup" "ac_cv_have_decl_strndup" "$ac_includes_default" +if test "x$ac_cv_have_decl_strndup" = x""yes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_STRNDUP $ac_have_decl +_ACEOF +ac_fn_cxx_check_decl "$LINENO" "memmem" "ac_cv_have_decl_memmem" "$ac_includes_default" +if test "x$ac_cv_have_decl_memmem" = x""yes; then : + ac_have_decl=1 +else + ac_have_decl=0 +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_MEMMEM $ac_have_decl +_ACEOF + + +# Use of ::std::tr1::unordered_map::rehash causes undefined symbols +# at link time with some versions of GCC. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ::std::tr1::unordered_map::rehash is usable." >&5 +$as_echo_n "checking whether ::std::tr1::unordered_map::rehash is usable.... " >&6; } +if test "${gold_cv_unordered_map_rehash+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +void bar() { ::std::tr1::unordered_map x; x.rehash(10); } + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_link "$LINENO"; then : + gold_cv_unordered_map_rehash=yes +else + gold_cv_unordered_map_rehash=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gold_cv_unordered_map_rehash" >&5 +$as_echo "$gold_cv_unordered_map_rehash" >&6; } +if test "$gold_cv_unordered_map_rehash" = "yes"; then + +$as_echo "#define HAVE_TR1_UNORDERED_MAP_REHASH 1" >>confdefs.h + +fi + +# Use of tr1/unordered_map with off_t as a key is not supported on GCC +# 4.1.xx when compiling in 32-bit mode with a 64-bit off_t type. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether std::tr1::hash is defined" >&5 +$as_echo_n "checking whether std::tr1::hash is defined... " >&6; } +if test "${gold_cv_hash_off_t+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + CXXFLAGS_hold=$CXXFLAGS +CXXFLAGS="$CXXFLAGS $LFS_CFLAGS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +std::tr1::hash h; + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + gold_cv_hash_off_t=yes +else + gold_cv_hash_off_t=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +CXXFLAGS=$CXXFLAGS_hold +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gold_cv_hash_off_t" >&5 +$as_echo "$gold_cv_hash_off_t" >&6; } +if test "$gold_cv_hash_off_t" = "yes"; then + +$as_echo "#define HAVE_TR1_HASH_OFF_T 1" >>confdefs.h + +fi + +# gcc 4.3.0 doesn't recognize the printf attribute on a template +# function. Check for that. This is gcc bug 35546. This test can +# probably be removed after the bug has been fixed for a while. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we can use attributes with template functions" >&5 +$as_echo_n "checking whether we can use attributes with template functions... " >&6; } +if test "${gold_cv_template_attribute+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +template extern void foo(const char*, ...) + __attribute__ ((__format__ (__printf__, 1, 2))); +template void foo(const char* format, ...) {} +void bar() { foo("%s\n", "foo"); } + +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + gold_cv_template_attribute=yes +else + gold_cv_template_attribute=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gold_cv_template_attribute" >&5 +$as_echo "$gold_cv_template_attribute" >&6; } +if test "$gold_cv_template_attribute" = "yes"; then + +$as_echo "#define HAVE_TEMPLATE_ATTRIBUTES 1" >>confdefs.h + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for struct stat::st_mtim." >&5 +$as_echo_n "checking for struct stat::st_mtim.... " >&6; } +if test "${gold_cv_stat_st_mtim+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +long bar() { struct stat s; return (long)(s.st_mtim.tv_sec + s.st_mtim.tv_sec);} + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + gold_cv_stat_st_mtim=yes +else + gold_cv_stat_st_mtim=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gold_cv_stat_st_mtim" >&5 +$as_echo "$gold_cv_stat_st_mtim" >&6; } +if test "$gold_cv_stat_st_mtim" = "yes"; then + +$as_echo "#define HAVE_STAT_ST_MTIM 1" >>confdefs.h + +fi + +save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS -Werror -gpubnames" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +int i; +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + have_pubnames=yes +else + have_pubnames=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +CXXFLAGS="$save_CXXFLAGS" + if test "$have_pubnames" = "yes"; then + HAVE_PUBNAMES_TRUE= + HAVE_PUBNAMES_FALSE='#' +else + HAVE_PUBNAMES_TRUE='#' + HAVE_PUBNAMES_FALSE= +fi + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +for ac_header in locale.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "locale.h" "ac_cv_header_locale_h" "$ac_includes_default" +if test "x$ac_cv_header_locale_h" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LOCALE_H 1 +_ACEOF + +fi + +done + +for ac_func in setlocale +do : + ac_fn_c_check_func "$LINENO" "setlocale" "ac_cv_func_setlocale" +if test "x$ac_cv_func_setlocale" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_SETLOCALE 1 +_ACEOF + +fi +done + + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LC_MESSAGES" >&5 +$as_echo_n "checking for LC_MESSAGES... " >&6; } +if test "${am_cv_val_LC_MESSAGES+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +return LC_MESSAGES + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + am_cv_val_LC_MESSAGES=yes +else + am_cv_val_LC_MESSAGES=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_val_LC_MESSAGES" >&5 +$as_echo "$am_cv_val_LC_MESSAGES" >&6; } + if test $am_cv_val_LC_MESSAGES = yes; then + +$as_echo "#define HAVE_LC_MESSAGES 1" >>confdefs.h + + fi + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5 +$as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; } + # Check whether --enable-maintainer-mode was given. +if test "${enable_maintainer_mode+set}" = set; then : + enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval +else + USE_MAINTAINER_MODE=no +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5 +$as_echo "$USE_MAINTAINER_MODE" >&6; } + if test $USE_MAINTAINER_MODE = yes; then + MAINTAINER_MODE_TRUE= + MAINTAINER_MODE_FALSE='#' +else + MAINTAINER_MODE_TRUE='#' + MAINTAINER_MODE_FALSE= +fi + + MAINT=$MAINTAINER_MODE_TRUE + + + +ac_config_files="$ac_config_files Makefile testsuite/Makefile po/Makefile.in:po/Make-in" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + test "x$cache_file" != "x/dev/null" && + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + cat confcache >$cache_file + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + if test -n "$EXEEXT"; then + am__EXEEXT_TRUE= + am__EXEEXT_FALSE='#' +else + am__EXEEXT_TRUE='#' + am__EXEEXT_FALSE= +fi + +if test -z "${THREADS_TRUE}" && test -z "${THREADS_FALSE}"; then + as_fn_error "conditional \"THREADS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${PLUGINS_TRUE}" && test -z "${PLUGINS_FALSE}"; then + as_fn_error "conditional \"PLUGINS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${DEFAULT_TARGET_ARM_TRUE}" && test -z "${DEFAULT_TARGET_ARM_FALSE}"; then + as_fn_error "conditional \"DEFAULT_TARGET_ARM\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${DEFAULT_TARGET_I386_TRUE}" && test -z "${DEFAULT_TARGET_I386_FALSE}"; then + as_fn_error "conditional \"DEFAULT_TARGET_I386\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${DEFAULT_TARGET_POWERPC_TRUE}" && test -z "${DEFAULT_TARGET_POWERPC_FALSE}"; then + as_fn_error "conditional \"DEFAULT_TARGET_POWERPC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${DEFAULT_TARGET_SPARC_TRUE}" && test -z "${DEFAULT_TARGET_SPARC_FALSE}"; then + as_fn_error "conditional \"DEFAULT_TARGET_SPARC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${DEFAULT_TARGET_X86_64_TRUE}" && test -z "${DEFAULT_TARGET_X86_64_FALSE}"; then + as_fn_error "conditional \"DEFAULT_TARGET_X86_64\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${DEFAULT_TARGET_TILEGX_TRUE}" && test -z "${DEFAULT_TARGET_TILEGX_FALSE}"; then + as_fn_error "conditional \"DEFAULT_TARGET_TILEGX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + as_fn_error "conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + as_fn_error "conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + as_fn_error "conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi + +if test -z "${NATIVE_LINKER_TRUE}" && test -z "${NATIVE_LINKER_FALSE}"; then + as_fn_error "conditional \"NATIVE_LINKER\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${GCC_TRUE}" && test -z "${GCC_FALSE}"; then + as_fn_error "conditional \"GCC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${NATIVE_OR_CROSS_LINKER_TRUE}" && test -z "${NATIVE_OR_CROSS_LINKER_FALSE}"; then + as_fn_error "conditional \"NATIVE_OR_CROSS_LINKER\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_STATIC_TRUE}" && test -z "${HAVE_STATIC_FALSE}"; then + as_fn_error "conditional \"HAVE_STATIC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${FN_PTRS_IN_SO_WITHOUT_PIC_TRUE}" && test -z "${FN_PTRS_IN_SO_WITHOUT_PIC_FALSE}"; then + as_fn_error "conditional \"FN_PTRS_IN_SO_WITHOUT_PIC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${MCMODEL_MEDIUM_TRUE}" && test -z "${MCMODEL_MEDIUM_FALSE}"; then + as_fn_error "conditional \"MCMODEL_MEDIUM\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${TLS_TRUE}" && test -z "${TLS_FALSE}"; then + as_fn_error "conditional \"TLS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${STATIC_TLS_TRUE}" && test -z "${STATIC_TLS_FALSE}"; then + as_fn_error "conditional \"STATIC_TLS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${OMP_SUPPORT_TRUE}" && test -z "${OMP_SUPPORT_FALSE}"; then + as_fn_error "conditional \"OMP_SUPPORT\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${TLS_GNU2_DIALECT_TRUE}" && test -z "${TLS_GNU2_DIALECT_FALSE}"; then + as_fn_error "conditional \"TLS_GNU2_DIALECT\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${TLS_DESCRIPTORS_TRUE}" && test -z "${TLS_DESCRIPTORS_FALSE}"; then + as_fn_error "conditional \"TLS_DESCRIPTORS\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${IFUNC_TRUE}" && test -z "${IFUNC_FALSE}"; then + as_fn_error "conditional \"IFUNC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${IFUNC_STATIC_TRUE}" && test -z "${IFUNC_STATIC_FALSE}"; then + as_fn_error "conditional \"IFUNC_STATIC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_ZLIB_TRUE}" && test -z "${HAVE_ZLIB_FALSE}"; then + as_fn_error "conditional \"HAVE_ZLIB\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${HAVE_PUBNAMES_TRUE}" && test -z "${HAVE_PUBNAMES_FALSE}"; then + as_fn_error "conditional \"HAVE_PUBNAMES\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then + as_fn_error "conditional \"MAINTAINER_MODE\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi + +: ${CONFIG_STATUS=./config.status} +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error ERROR [LINENO LOG_FD] +# --------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with status $?, using 1 if that was 0. +as_fn_error () +{ + as_status=$?; test $as_status -eq 0 && as_status=1 + if test "$3"; then + as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 + fi + $as_echo "$as_me: error: $1" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by gold $as_me 0.1, which was +generated by GNU Autoconf 2.64. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + +case $ac_config_headers in *" +"*) set x $ac_config_headers; shift; ac_config_headers=$*;; +esac + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Configuration commands: +$config_commands + +Report bugs to the package provider." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_version="\\ +gold config.status 0.1 +configured by $0, generated by GNU Autoconf 2.64, + with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2009 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' +AWK='$AWK' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_HEADERS " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + as_fn_error "ambiguous option: \`$1' +Try \`$0 --help' for more information.";; + --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" +# Capture the value of obsolete ALL_LINGUAS because we need it to compute + # POFILES, GMOFILES, UPDATEPOFILES, DUMMYPOFILES, CATALOGS. But hide it + # from automake. + eval 'OBSOLETE_ALL_LINGUAS''="$ALL_LINGUAS"' + # Capture the value of LINGUAS because we need it to compute CATALOGS. + LINGUAS="${LINGUAS-%UNSET%}" + + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h:config.in" ;; + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "default-1") CONFIG_COMMANDS="$CONFIG_COMMANDS default-1" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "testsuite/Makefile") CONFIG_FILES="$CONFIG_FILES testsuite/Makefile" ;; + "po/Makefile.in") CONFIG_FILES="$CONFIG_FILES po/Makefile.in:po/Make-in" ;; + + *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error "cannot create a temporary directory in ." "$LINENO" 5 + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\).*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\).*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ + || as_fn_error "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/ +s/:*\${srcdir}:*/:/ +s/:*@srcdir@:*/:/ +s/^\([^=]*=[ ]*\):*/\1/ +s/:*$// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + +# Set up the scripts for CONFIG_HEADERS section. +# No need to generate them if there are no CONFIG_HEADERS. +# This happens for instance with `./config.status Makefile'. +if test -n "$CONFIG_HEADERS"; then +cat >"$tmp/defines.awk" <<\_ACAWK || +BEGIN { +_ACEOF + +# Transform confdefs.h into an awk script `defines.awk', embedded as +# here-document in config.status, that substitutes the proper values into +# config.h.in to produce config.h. + +# Create a delimiter string that does not exist in confdefs.h, to ease +# handling of long lines. +ac_delim='%!_!# ' +for ac_last_try in false false :; do + ac_t=`sed -n "/$ac_delim/p" confdefs.h` + if test -z "$ac_t"; then + break + elif $ac_last_try; then + as_fn_error "could not make $CONFIG_HEADERS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +# For the awk script, D is an array of macro values keyed by name, +# likewise P contains macro parameters if any. Preserve backslash +# newline sequences. + +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +sed -n ' +s/.\{148\}/&'"$ac_delim"'/g +t rset +:rset +s/^[ ]*#[ ]*define[ ][ ]*/ / +t def +d +:def +s/\\$// +t bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3"/p +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p +d +:bsnl +s/["\\]/\\&/g +s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ +D["\1"]=" \3\\\\\\n"\\/p +t cont +s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p +t cont +d +:cont +n +s/.\{148\}/&'"$ac_delim"'/g +t clear +:clear +s/\\$// +t bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/"/p +d +:bsnlc +s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p +b cont +' >$CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + for (key in D) D_is_set[key] = 1 + FS = "" +} +/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { + line = \$ 0 + split(line, arg, " ") + if (arg[1] == "#") { + defundef = arg[2] + mac1 = arg[3] + } else { + defundef = substr(arg[1], 2) + mac1 = arg[2] + } + split(mac1, mac2, "(") #) + macro = mac2[1] + prefix = substr(line, 1, index(line, defundef) - 1) + if (D_is_set[macro]) { + # Preserve the white space surrounding the "#". + print prefix "define", macro P[macro] D[macro] + next + } else { + # Replace #undef with comments. This is necessary, for example, + # in the case of _POSIX_SOURCE, which is predefined and required + # on some systems where configure will not decide to define it. + if (defundef == "undef") { + print "/*", prefix defundef, macro, "*/" + next + } + } +} +{ print } +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + as_fn_error "could not setup config headers machinery" "$LINENO" 5 +fi # test -n "$CONFIG_HEADERS" + + +eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin" \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&2;} + + rm -f "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out" && rm -f "$tmp/out";; + *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; + esac \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 + ;; + :H) + # + # CONFIG_HEADER + # + if test x"$ac_file" != x-; then + { + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" + } >"$tmp/config.h" \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 + if diff "$ac_file" "$tmp/config.h" >/dev/null 2>&1; then + { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 +$as_echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f "$ac_file" + mv "$tmp/config.h" "$ac_file" \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 + fi + else + $as_echo "/* $configure_input */" \ + && eval '$AWK -f "$tmp/defines.awk"' "$ac_file_inputs" \ + || as_fn_error "could not create -" "$LINENO" 5 + fi +# Compute "$ac_file"'s index in $config_headers. +_am_arg="$ac_file" +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || +$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$_am_arg" : 'X\(//\)[^/]' \| \ + X"$_am_arg" : 'X\(//\)$' \| \ + X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$_am_arg" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'`/stamp-h$_am_stamp_count + ;; + + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || { + # Autoconf 2.62 quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir=$dirpart/$fdir; as_fn_mkdir_p + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} + ;; + "default-1":C) + for ac_file in $CONFIG_FILES; do + # Support "outfile[:infile[:infile...]]" + case "$ac_file" in + *:*) ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;; + esac + # PO directories have a Makefile.in generated from Makefile.in.in. + case "$ac_file" in */Makefile.in) + # Adjust a relative srcdir. + ac_dir=`echo "$ac_file"|sed 's%/[^/][^/]*$%%'` + ac_dir_suffix=/`echo "$ac_dir"|sed 's%^\./%%'` + ac_dots=`echo "$ac_dir_suffix"|sed 's%/[^/]*%../%g'` + # In autoconf-2.13 it is called $ac_given_srcdir. + # In autoconf-2.50 it is called $srcdir. + test -n "$ac_given_srcdir" || ac_given_srcdir="$srcdir" + case "$ac_given_srcdir" in + .) top_srcdir=`echo $ac_dots|sed 's%/$%%'` ;; + /*) top_srcdir="$ac_given_srcdir" ;; + *) top_srcdir="$ac_dots$ac_given_srcdir" ;; + esac + if test -f "$ac_given_srcdir/$ac_dir/POTFILES.in"; then + rm -f "$ac_dir/POTFILES" + test -n "$as_me" && echo "$as_me: creating $ac_dir/POTFILES" || echo "creating $ac_dir/POTFILES" + cat "$ac_given_srcdir/$ac_dir/POTFILES.in" | sed -e "/^#/d" -e "/^[ ]*\$/d" -e "s,.*, $top_srcdir/& \\\\," | sed -e "\$s/\(.*\) \\\\/\1/" > "$ac_dir/POTFILES" + POMAKEFILEDEPS="POTFILES.in" + # ALL_LINGUAS, POFILES, GMOFILES, UPDATEPOFILES, DUMMYPOFILES depend + # on $ac_dir but don't depend on user-specified configuration + # parameters. + if test -f "$ac_given_srcdir/$ac_dir/LINGUAS"; then + # The LINGUAS file contains the set of available languages. + if test -n "$OBSOLETE_ALL_LINGUAS"; then + test -n "$as_me" && echo "$as_me: setting ALL_LINGUAS in configure.in is obsolete" || echo "setting ALL_LINGUAS in configure.in is obsolete" + fi + ALL_LINGUAS_=`sed -e "/^#/d" "$ac_given_srcdir/$ac_dir/LINGUAS"` + # Hide the ALL_LINGUAS assigment from automake. + eval 'ALL_LINGUAS''=$ALL_LINGUAS_' + POMAKEFILEDEPS="$POMAKEFILEDEPS LINGUAS" + else + # The set of available languages was given in configure.in. + eval 'ALL_LINGUAS''=$OBSOLETE_ALL_LINGUAS' + fi + case "$ac_given_srcdir" in + .) srcdirpre= ;; + *) srcdirpre='$(srcdir)/' ;; + esac + POFILES= + GMOFILES= + UPDATEPOFILES= + DUMMYPOFILES= + for lang in $ALL_LINGUAS; do + POFILES="$POFILES $srcdirpre$lang.po" + GMOFILES="$GMOFILES $srcdirpre$lang.gmo" + UPDATEPOFILES="$UPDATEPOFILES $lang.po-update" + DUMMYPOFILES="$DUMMYPOFILES $lang.nop" + done + # CATALOGS depends on both $ac_dir and the user's LINGUAS + # environment variable. + INST_LINGUAS= + if test -n "$ALL_LINGUAS"; then + for presentlang in $ALL_LINGUAS; do + useit=no + if test "%UNSET%" != "$LINGUAS"; then + desiredlanguages="$LINGUAS" + else + desiredlanguages="$ALL_LINGUAS" + fi + for desiredlang in $desiredlanguages; do + # Use the presentlang catalog if desiredlang is + # a. equal to presentlang, or + # b. a variant of presentlang (because in this case, + # presentlang can be used as a fallback for messages + # which are not translated in the desiredlang catalog). + case "$desiredlang" in + "$presentlang"*) useit=yes;; + esac + done + if test $useit = yes; then + INST_LINGUAS="$INST_LINGUAS $presentlang" + fi + done + fi + CATALOGS= + if test -n "$INST_LINGUAS"; then + for lang in $INST_LINGUAS; do + CATALOGS="$CATALOGS $lang.gmo" + done + fi + test -n "$as_me" && echo "$as_me: creating $ac_dir/Makefile" || echo "creating $ac_dir/Makefile" + sed -e "/^POTFILES =/r $ac_dir/POTFILES" -e "/^# Makevars/r $ac_given_srcdir/$ac_dir/Makevars" -e "s|@POFILES@|$POFILES|g" -e "s|@GMOFILES@|$GMOFILES|g" -e "s|@UPDATEPOFILES@|$UPDATEPOFILES|g" -e "s|@DUMMYPOFILES@|$DUMMYPOFILES|g" -e "s|@CATALOGS@|$CATALOGS|g" -e "s|@POMAKEFILEDEPS@|$POMAKEFILEDEPS|g" "$ac_dir/Makefile.in" > "$ac_dir/Makefile" + for f in "$ac_given_srcdir/$ac_dir"/Rules-*; do + if test -f "$f"; then + case "$f" in + *.orig | *.bak | *~) ;; + *) cat "$f" >> "$ac_dir/Makefile" ;; + esac + fi + done + fi + ;; + esac + done ;; + + esac +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit $? +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + diff --git a/binutils-2.25/gold/configure.ac b/binutils-2.25/gold/configure.ac new file mode 100644 index 00000000..c23117b6 --- /dev/null +++ b/binutils-2.25/gold/configure.ac @@ -0,0 +1,619 @@ +dnl Process this file with autoconf to produce a configure script. +dnl +dnl Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 +dnl Free Software Foundation, Inc. +dnl +dnl This file is free software; you can redistribute it and/or modify +dnl it under the terms of the GNU General Public License as published by +dnl the Free Software Foundation; either version 3 of the License, or +dnl (at your option) any later version. +dnl +dnl This program is distributed in the hope that it will be useful, +dnl but WITHOUT ANY WARRANTY; without even the implied warranty of +dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +dnl GNU General Public License for more details. +dnl +dnl You should have received a copy of the GNU General Public License +dnl along with this program; see the file COPYING3. If not see +dnl . +dnl + +AC_PREREQ(2.59) + +AC_INIT(gold, 0.1) +AC_CONFIG_SRCDIR(gold.cc) + +AC_CANONICAL_TARGET + +AM_INIT_AUTOMAKE([no-dist parallel-tests]) + +AM_CONFIG_HEADER(config.h:config.in) + +# PR 14072 +AH_VERBATIM([00_CONFIG_H_CHECK], +[/* Check that config.h is #included before system headers + (this works only for glibc, but that should be enough). */ +#if defined(__GLIBC__) && !defined(__FreeBSD_kernel__) && !defined(__CONFIG_H__) +# error config.h must be #included before system headers +#endif +#define __CONFIG_H__ 1]) + +AC_ARG_WITH(sysroot, +[ --with-sysroot[=DIR] search for usr/lib et al within DIR], +[sysroot=$withval], [sysroot=no]) + +if test "$sysroot" = "yes"; then + sysroot='${exec_prefix}/${target_alias}/sys-root' +elif test "$sysroot" = "no"; then + sysroot= +fi + +sysroot_relocatable=0 +if test -n "$sysroot"; then + case "sysroot" in + "${prefix}" | "${prefix}/"* | \ + "${exec_prefix}" | "${exec_prefix}/"* | \ + '${prefix}' | '${prefix}/'*| \ + '${exec_prefix}' | '${exec_prefix}/'*) + sysroot_relocatable=1 + ;; + esac +fi + +AC_DEFINE_UNQUOTED(TARGET_SYSTEM_ROOT, "$sysroot", + [System root for target files]) +AC_DEFINE_UNQUOTED(TARGET_SYSTEM_ROOT_RELOCATABLE, $sysroot_relocatable, + [Whether the system root can be relocated]) + +dnl "install_as_default" is true if the linker to be installed as the +dnl default linker, ld. +dnl "installed_linker" is the installed gold linker name. + +installed_linker=ld.gold +AC_ARG_ENABLE(gold, +[[ --enable-gold[=ARG] build gold [ARG={default,yes,no}]]], +[case "${enableval}" in + default) + install_as_default=yes + ;; + yes) + if test x${enable_ld} = xno; then + install_as_default=yes + fi + ;; + esac], +[install_as_default=no]) +AC_SUBST(install_as_default) +AC_SUBST(installed_linker) + +dnl For now threads are a configure time option. +AC_ARG_ENABLE([threads], +[ --enable-threads multi-threaded linking], +[case "${enableval}" in + yes | "") threads=yes ;; + no) threads=no ;; + *) threads=yes ;; + esac], +[threads=no]) +if test "$threads" = "yes"; then + AC_DEFINE(ENABLE_THREADS, 1, + [Define to do multi-threaded linking]) +fi +AM_CONDITIONAL(THREADS, test "$threads" = "yes") + +AC_ARG_ENABLE([plugins], +[ --enable-plugins linker plugins], +[case "${enableval}" in + yes | "") plugins=yes ;; + no) plugins=no ;; + *) plugins=yes ;; + esac], +[plugins=no]) +if test "$plugins" = "yes"; then + AC_DEFINE(ENABLE_PLUGINS, 1, + [Define to enable linker plugins]) +fi +AM_CONDITIONAL(PLUGINS, test "$plugins" = "yes") + +AC_ARG_ENABLE([targets], +[ --enable-targets alternative target configurations], +[case "${enableval}" in + yes | "") + AC_MSG_ERROR([--enable-targets option must specify target names or 'all']) + ;; + no) + enable_targets= + ;; + *) + enable_targets=$enableval + ;; +esac], +[# For now, enable all targets by default + enable_targets=all +]) + +# Canonicalize the enabled targets. +if test -n "$enable_targets"; then + for targ in `echo $enable_targets | sed -e 's/,/ /g'`; do + result=`$ac_config_sub $targ 2>/dev/null` + if test -n "$result"; then + canon_targets="$canon_targets $result" + else + # Permit unrecognized target names, like "all". + canon_targets="$canon_targets $targ" + fi + done +fi + +# See which specific instantiations we need. +targetobjs= +all_targets= +default_machine= +default_size= +default_big_endian= +default_osabi=ELFOSABI_NONE +targ_32_little= +targ_32_big= +targ_64_little= +targ_64_big= +for targ in $target $canon_targets; do + if test "$targ" = "all"; then + targ_32_little=yes + targ_32_big=yes + targ_64_little=yes + targ_64_big=yes + all_targets=yes + else + . ${srcdir}/configure.tgt + + if test "$targ_obj" = "UNKNOWN"; then + AC_MSG_ERROR("unsupported target $targ") + else + targetobjs="$targetobjs ${targ_obj}.\$(OBJEXT)" + if test "$targ_extra_obj" != ""; then + targetobjs="$targetobjs ${targ_extra_obj}.\$(OBJEXT)" + fi + if test "$targ_size" = "32" -o "$targ_extra_size" = "32"; then + if test "$targ_big_endian" = "true" \ + -o "$targ_extra_big_endian" = "true"; then + targ_32_big=yes + fi + if test "$targ_big_endian" = "false" \ + -o "$targ_extra_big_endian" = "false"; then + targ_32_little=yes + fi + fi + if test "$targ_size" = "64" -o "$targ_extra_size" = "64"; then + if test "$targ_big_endian" = "true" \ + -o "$targ_extra_big_endian" = "true"; then + targ_64_big=yes + fi + if test "$targ_big_endian" = "false" \ + -o "$targ_extra_big_endian" = "false"; then + targ_64_little=yes + fi + fi + + if test "$target" = "$targ"; then + default_machine=$targ_machine + default_size=$targ_size + default_big_endian=$targ_big_endian + default_osabi=$targ_osabi + + AM_CONDITIONAL(DEFAULT_TARGET_ARM, test "$targ_obj" = "arm") + AM_CONDITIONAL(DEFAULT_TARGET_I386, test "$targ_obj" = "i386") + AM_CONDITIONAL(DEFAULT_TARGET_POWERPC, test "$targ_obj" = "powerpc") + AM_CONDITIONAL(DEFAULT_TARGET_SPARC, test "$targ_obj" = "sparc") + AM_CONDITIONAL(DEFAULT_TARGET_X86_64, test "$targ_obj" = "x86_64") + AM_CONDITIONAL(DEFAULT_TARGET_TILEGX, test "$targ_obj" = "tilegx") + DEFAULT_TARGET=${targ_obj} + AC_SUBST(DEFAULT_TARGET) + fi + fi + fi +done + +# Remove any duplicates. +to="" +for t in $targetobjs; do + case " $to " in + *" $t "*) ;; + *) to="$to $t" ;; + esac +done +targetobjs=$to + +if test -n "$targ_32_little"; then + AC_DEFINE(HAVE_TARGET_32_LITTLE, 1, + [Define to support 32-bit little-endian targets]) +fi +if test -n "$targ_32_big"; then + AC_DEFINE(HAVE_TARGET_32_BIG, 1, + [Define to support 32-bit big-endian targets]) +fi +if test -n "$targ_64_little"; then + AC_DEFINE(HAVE_TARGET_64_LITTLE, 1, + [Define to support 64-bit little-endian targets]) +fi +if test -n "$targ_64_big"; then + AC_DEFINE(HAVE_TARGET_64_BIG, 1, + [Define to support 64-bit big-endian targets]) +fi + +if test -n "$all_targets"; then + TARGETOBJS='$(ALL_TARGETOBJS)' +else + TARGETOBJS="$targetobjs" +fi +AC_SUBST(TARGETOBJS) + +AC_DEFINE_UNQUOTED(GOLD_DEFAULT_MACHINE, $default_machine, + [Default machine code]) +AC_DEFINE_UNQUOTED(GOLD_DEFAULT_SIZE, $default_size, + [Default size (32 or 64)]) +AC_DEFINE_UNQUOTED(GOLD_DEFAULT_BIG_ENDIAN, $default_big_endian, + [Default big endian (true or false)]) +AC_DEFINE_UNQUOTED(GOLD_DEFAULT_OSABI, $default_osabi, + [Default OSABI code]) + +AC_ARG_WITH(lib-path, +[ --with-lib-path=dir1:dir2... set default LIB_PATH], +[case "$withval" in + yes) LIB_PATH='"/lib:/usr/lib"' ;; + no) LIB_PATH='""' ;; + *) LIB_PATH='"'"$withval"'"' ;; + esac], +[LIB_PATH='"::DEFAULT::"']) +AC_DEFINE_UNQUOTED(LIB_PATH, $LIB_PATH, + [Default library search path]) +if test "x$target_alias" = "x" -o "x$host_alias" = "x$target_alias"; then + AC_DEFINE(NATIVE_LINKER, 1, [Whether configured as a native linker]) +fi + +AC_CHECK_TOOL(NM, nm) + +AC_PROG_CC +AC_PROG_CXX +AC_PROG_YACC +AC_PROG_RANLIB +AC_PROG_INSTALL +AC_PROG_LN_S + +AC_GNU_SOURCE + +ZW_GNU_GETTEXT_SISTER_DIR +AM_PO_SUBDIRS + +AC_C_BIGENDIAN + +AC_EXEEXT + +AM_CONDITIONAL(NATIVE_LINKER, + test "x$target_alias" = "x" -o "x$host_alias" = "x$target_alias") +AM_CONDITIONAL(GCC, test "$GCC" = yes) + +AM_CONDITIONAL(NATIVE_OR_CROSS_LINKER, + test "x$target_alias" = "x" -o "x$host_alias" = "x$target_alias" -o "x$host_alias" = "x$build_alias") + +dnl Test for whether static linking is supported. Some systems do not +dnl install static libraries. This only affects the set of tests that +dnl we run. +AC_CACHE_CHECK([whether static linking works], [gold_cv_lib_static], +[LDFLAGS_hold=$LDFLAGS +LDFLAGS="$LDFLAGS -static" +AC_LINK_IFELSE([ +AC_LANG_PROGRAM([[void f() { }]])], +[gold_cv_lib_static=yes], [gold_cv_lib_static=no]) +LDFLAGS=$LDFLAGS_hold]) +AM_CONDITIONAL(HAVE_STATIC, test "$gold_cv_lib_static" = "yes") + +dnl Some architectures do not support taking pointers of functions +dnl defined in shared libraries except in -fPIC mode. We need to +dnl tell the unittest framework if we're compiling for one of those +dnl targets, so it doesn't try to run the tests that do that. +AM_CONDITIONAL(FN_PTRS_IN_SO_WITHOUT_PIC, [ + case $target_cpu in + powerpc*) false;; + x86_64) false;; + sparc64) false;; + *) true;; + esac]) + +dnl Test for gcc 4.1 or later. Full support for -mcmodel=medium is +dnl only available in gcc 4.1. +AC_CACHE_CHECK([for gcc >= 4.1], [gold_cv_prog_gcc41], +[AC_COMPILE_IFELSE([ +#if !defined __GNUC__ +error +#elif __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 1) +error +#endif +], [gold_cv_prog_gcc41=yes], [gold_cv_prog_gcc41=no])]) + +save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -mcmodel=medium" +AC_COMPILE_IFELSE([int i;], [have_mcmodel_medium=yes], [have_mcmodel_medium=no]) +CFLAGS="$save_CFLAGS" +dnl Whether we can test -mcmodel=medium. +AM_CONDITIONAL(MCMODEL_MEDIUM, +[test "$target_cpu" = "x86_64" -a "$have_mcmodel_medium" = "yes" -a "$gold_cv_prog_gcc41" = "yes"]) + +AC_CACHE_CHECK([whether $CC supports -fmerge-constants], + [gold_cv_merge_constants], [ +save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -fmerge-constants" +AC_COMPILE_IFELSE([const char *s = "foo";], + [have_merge_constants=yes], + [have_merge_constants=no]) +CFLAGS="$save_CFLAGS"]) +AC_SUBST([MERGE_CONSTANTS_FLAG]) +AS_IF([test "$gold_cv_merge_constants" = yes], + [MERGE_CONSTANTS_FLAG=-fmerge-constants], + [MERGE_CONSTANTS_FLAG=]) + +dnl Test for __thread support. +AC_CACHE_CHECK([for thread support], [gold_cv_c_thread], +[AC_COMPILE_IFELSE([__thread int i = 1;], +[gold_cv_c_thread=yes], [gold_cv_c_thread=no])]) + +AM_CONDITIONAL(TLS, test "$gold_cv_c_thread" = "yes") + +dnl On GNU/Linux TLS in static programs only works when using glibc +dnl 2.4 or later. +AC_CACHE_CHECK([for glibc >= 2.4], [gold_cv_lib_glibc24], +[AC_COMPILE_IFELSE([ +#include +#if !defined __GLIBC__ +error +#elif __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 4) +error +#endif +], [gold_cv_lib_glibc24=yes], [gold_cv_lib_glibc24=no])]) + +AM_CONDITIONAL(STATIC_TLS, test "$gold_cv_lib_glibc24" = "yes") + +dnl Test for #pragma omp threadprivate +AC_CACHE_CHECK([for omp support], [gold_cv_c_threadprivate], +[save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -fopenmp" +AC_COMPILE_IFELSE([ +#include +int i; +#pragma omp threadprivate (i) +], [gold_cv_c_threadprivate=yes], [gold_cv_c_threadprivate=no]) +CFLAGS="$save_CFLAGS"]) +if test "$gold_cv_c_threadprivate" = "yes"; then + AC_DEFINE(HAVE_OMP_SUPPORT, 1, + [Define if compiler supports #pragma omp threadprivate]) +fi +AM_CONDITIONAL(OMP_SUPPORT, test "$gold_cv_c_threadprivate" = "yes") + +dnl Test for the -ftls-dialect=gnu2 option. +dnl Use -Werror in case of compilers that make unknown -m options warnings. +dnl They would pass the test here, but fail in actual use when $WARN_CFLAGS +dnl gets set later by default Autoconf magic to include -Werror. (We are +dnl assuming here that there is no compiler that groks -mtls-dialect=gnu2 +dnl but does not grok -Werror.) +save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -Werror -fpic -mtls-dialect=gnu2" +AC_COMPILE_IFELSE([ +__thread int i; +void foo (void) +{ + i = 10; +} +], [have_tls_gnu2=yes], [have_tls_gnu2=no]) +CFLAGS="$save_CFLAGS" +AM_CONDITIONAL(TLS_GNU2_DIALECT, test "$have_tls_gnu2" = "yes") + +dnl On GNU/Linux TLS descriptors are supported by the dynamic loader +dnl only with glibc 2.9 or later. +AC_CACHE_CHECK([for glibc >= 2.9], [gold_cv_lib_glibc29], +[AC_COMPILE_IFELSE([ +#include +#if !defined __GLIBC__ +error +#elif __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 9) +error +#endif +], [gold_cv_lib_glibc29=yes], [gold_cv_lib_glibc29=no])]) + +AM_CONDITIONAL(TLS_DESCRIPTORS, test "$gold_cv_lib_glibc29" = "yes") + +dnl Test for the -frandom-seed option. +AC_CACHE_CHECK([for -frandom-seed support], [gold_cv_c_random_seed], +[save_CFLAGS="$CFLAGS" +CFLAGS="$CFLAGS -frandom-seed=foo" +AC_COMPILE_IFELSE([int i;], [gold_cv_c_random_seed=yes], +[gold_cv_c_random_seed=no]) +CFLAGS="$save_CFLAGS"]) +if test "$gold_cv_c_random_seed" = "yes"; then + # In Makefile, '$@' will be expanded to be the name of the file + # being built, providing a unique seed for each file. + RANDOM_SEED_CFLAGS=-frandom-seed=\$@ +fi +AC_SUBST(RANDOM_SEED_CFLAGS) + +dnl On GNU/Linux ifunc is supported by the dynamic linker in glibc +dnl 2.11 or later, and by binutils 2.20.1 or later. +AC_CACHE_CHECK([for glibc ifunc support], [gold_cv_lib_glibc_ifunc], +[save_LDFLAGS="$LDFLAGS" +LDFLAGS="$LDFLAGS -static" +AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#include +#if !defined __GLIBC__ +error +#elif __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 11) +error +#endif +void func (void) { } +void invoke (void); +__asm__(".type invoke, %gnu_indirect_function"); +typedef void (*funcptr) (void); +funcptr dispatch (void) __asm__ ("invoke"); +funcptr dispatch (void) { return &func; }]], +[[invoke();]]) +], [ +if ${NM} conftest$EXEEXT | grep "__rela\?_iplt_start" >/dev/null 2>&1; then + gold_cv_lib_glibc_ifunc=both +else + gold_cv_lib_glibc_ifunc=dyn +fi], [gold_cv_lib_glibc_ifunc=no]) +LDFLAGS="$save_LDFLAGS"]) + +AM_CONDITIONAL(IFUNC, test "$gold_cv_lib_glibc_ifunc" != "no") +AM_CONDITIONAL(IFUNC_STATIC, test "$gold_cv_lib_glibc_ifunc" = "both") + +AM_BINUTILS_WARNINGS + +WARN_CXXFLAGS=`echo ${WARN_CFLAGS} | sed -e 's/-Wstrict-prototypes//' -e 's/-Wmissing-prototypes//' -e 's/-Wshadow//'` +AC_SUBST(WARN_CXXFLAGS) + +AC_ARG_WITH(gold-ldflags, +[ --with-gold-ldflags=FLAGS additional link flags for gold], +[if test "$withval" = "no" -o "$withval" = "yes"; then + GOLD_LDFLAGS= + else + GOLD_LDFLAGS=$withval + fi], +[GOLD_LDFLAGS=]) +AC_SUBST(GOLD_LDFLAGS) + +AC_ARG_WITH(gold-ldadd, +[ --with-gold-ldadd=LIBS additional libraries for gold], +[if test "$withval" = "no" -o "$withval" = "yes"; then + GOLD_LDADD= + else + GOLD_LDADD=$withval + fi], +[GOLD_LDADD=]) +AC_SUBST(GOLD_LDADD) + +dnl Force support for large files by default. This may need to be +dnl host dependent. If build == host, we can check getconf LFS_CFLAGS. +LFS_CFLAGS="-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64" +AC_SUBST(LFS_CFLAGS) + +AC_CHECK_HEADERS(sys/mman.h) +AC_CHECK_FUNCS(chsize mmap) +AC_REPLACE_FUNCS(pread ftruncate ffsll) + +AC_CACHE_CHECK([mremap with MREMAP_MAYMOVE], [gold_cv_lib_mremap_maymove], +[AC_LINK_IFELSE([ +AC_LANG_PROGRAM([[ +#include +void f() { mremap (0, 0, 0, MREMAP_MAYMOVE); } +]])], [gold_cv_lib_mremap_maymove=yes], [gold_cv_lib_mremap_maymove=no])]) +if test "$gold_cv_lib_mremap_maymove" = "yes"; then + AC_DEFINE(HAVE_MREMAP, 1, + [Define to 1 if you have the mremap function with MREMAP_MAYMOVE support]) +else + AC_LIBOBJ(mremap) +fi + +# Link in zlib if we can. This allows us to write compressed sections. +AM_ZLIB +AM_CONDITIONAL(HAVE_ZLIB, test "$ac_cv_header_zlib_h" = "yes") + +dnl We have to check these in C, not C++, because autoconf generates +dnl tests which have no type information, and current glibc provides +dnl multiple declarations of functions like basename when compiling +dnl with C++. +AC_CHECK_DECLS([basename, ffs, asprintf, vasprintf, snprintf, vsnprintf, strverscmp]) + +AC_LANG_PUSH(C++) + +AC_CHECK_HEADERS(tr1/unordered_set tr1/unordered_map) +AC_CHECK_HEADERS(ext/hash_map ext/hash_set) +AC_CHECK_HEADERS(byteswap.h) + +dnl When plugins enabled dynamic loader interface is required. Check headers +dnl which may provide this interface. In case of dlfcn.h add libdl to link. +AC_CHECK_HEADERS(windows.h) +AC_CHECK_HEADERS(dlfcn.h, [DLOPEN_LIBS="-ldl"], [DLOPEN_LIBS=""]) +AC_SUBST(DLOPEN_LIBS) + +AC_CHECK_FUNCS(mallinfo posix_fallocate fallocate readv sysconf times) +AC_CHECK_DECLS([basename, ffs, asprintf, vasprintf, snprintf, vsnprintf, strverscmp, strndup, memmem]) + +# Use of ::std::tr1::unordered_map::rehash causes undefined symbols +# at link time with some versions of GCC. +AC_CACHE_CHECK([whether ::std::tr1::unordered_map::rehash is usable.], +[gold_cv_unordered_map_rehash], +[AC_LINK_IFELSE([AC_LANG_PROGRAM([[ +#include +void bar() { ::std::tr1::unordered_map x; x.rehash(10); } +]])], [gold_cv_unordered_map_rehash=yes], [gold_cv_unordered_map_rehash=no])]) +if test "$gold_cv_unordered_map_rehash" = "yes"; then + AC_DEFINE(HAVE_TR1_UNORDERED_MAP_REHASH, 1, + [Define if ::std::tr1::unordered_map::rehash is usable]) +fi + +# Use of tr1/unordered_map with off_t as a key is not supported on GCC +# 4.1.xx when compiling in 32-bit mode with a 64-bit off_t type. +AC_CACHE_CHECK([whether std::tr1::hash is defined], +[gold_cv_hash_off_t], +[CXXFLAGS_hold=$CXXFLAGS +CXXFLAGS="$CXXFLAGS $LFS_CFLAGS" +AC_COMPILE_IFELSE([ +#include +#include +std::tr1::hash h; +], +[gold_cv_hash_off_t=yes], +[gold_cv_hash_off_t=no]) +CXXFLAGS=$CXXFLAGS_hold]) +if test "$gold_cv_hash_off_t" = "yes"; then + AC_DEFINE(HAVE_TR1_HASH_OFF_T, 1, + [Define if std::tr1::hash is usable]) +fi + +# gcc 4.3.0 doesn't recognize the printf attribute on a template +# function. Check for that. This is gcc bug 35546. This test can +# probably be removed after the bug has been fixed for a while. +AC_CACHE_CHECK([whether we can use attributes with template functions], +[gold_cv_template_attribute], +[AC_COMPILE_IFELSE([ +template extern void foo(const char*, ...) + __attribute__ ((__format__ (__printf__, 1, 2))); +template void foo(const char* format, ...) {} +void bar() { foo("%s\n", "foo"); } +], [gold_cv_template_attribute=yes], [gold_cv_template_attribute=no])]) +if test "$gold_cv_template_attribute" = "yes"; then + AC_DEFINE(HAVE_TEMPLATE_ATTRIBUTES, 1, + [Define if attributes work on C++ templates]) +fi + +dnl Check if the system has struct stat::st_mtim. +AC_CACHE_CHECK([for struct stat::st_mtim.], +[gold_cv_stat_st_mtim], +[AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ +#include +long bar() { struct stat s; return (long)(s.st_mtim.tv_sec + s.st_mtim.tv_sec);} +]])], [gold_cv_stat_st_mtim=yes], [gold_cv_stat_st_mtim=no])]) +if test "$gold_cv_stat_st_mtim" = "yes"; then + AC_DEFINE(HAVE_STAT_ST_MTIM, 1, + [Define if struct stat has a field st_mtim with timespec for mtime]) +fi + +dnl Check if gcc supports the -gpubnames option. +dnl Use -Werror in case of compilers that make unknown -g options warnings. +dnl They would pass the test here, but fail in actual use when $WARN_CFLAGS +dnl gets set later by default Autoconf magic to include -Werror. (We are +dnl assuming here that there is no compiler that groks -gpubnames +dnl but does not grok -Werror.) +save_CXXFLAGS="$CXXFLAGS" +CXXFLAGS="$CXXFLAGS -Werror -gpubnames" +AC_COMPILE_IFELSE([int i;], [have_pubnames=yes], [have_pubnames=no]) +CXXFLAGS="$save_CXXFLAGS" +AM_CONDITIONAL(HAVE_PUBNAMES, test "$have_pubnames" = "yes") + +AC_LANG_POP(C++) + +AC_CHECK_HEADERS(locale.h) +AC_CHECK_FUNCS(setlocale) +AM_LC_MESSAGES + +AM_MAINTAINER_MODE + +AC_OUTPUT(Makefile testsuite/Makefile po/Makefile.in:po/Make-in) diff --git a/binutils-2.25/gold/configure.tgt b/binutils-2.25/gold/configure.tgt new file mode 100644 index 00000000..d61647e0 --- /dev/null +++ b/binutils-2.25/gold/configure.tgt @@ -0,0 +1,150 @@ +# configure.tgt -- target configuration for gold -*- sh -*- + +# Copyright 2006, 2007, 2008, 2009 Free Software Foundation, Inc. +# Written by Ian Lance Taylor . + +# 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. + +# This script handles target configuration for gold. This is shell +# code invoked by the autoconf generated configure script. Putting +# this in a separate file lets us skip running autoconf when modifying +# target specific information. + +# This file switches on the shell variable ${targ}, which is a +# canonicalized GNU configuration triplet. It sets the following +# shell variables: + +# targ_obj object file to include in the link, with no extension +# targ_extra_obj extra object file to include +# targ_machine ELF machine code for this target +# targ_size size of this target--32 or 64 +# targ_extra_size extra targ_size setting for the target +# targ_big_endian whether the target is big-endian--true or false +# targ_extra_big_endian extra targ_big_endian setting for the target +# targ_osabi EI_OSABI value + +# If the target is not recognized targ_obj is set to "UNKNOWN". + +targ_extra_obj= +targ_machine= +targ_size= +targ_extra_size= +targ_big_endian= +targ_extra_big_endian= +targ_osabi=ELFOSABI_NONE +case "$targ" in +i?86-*) + targ_obj=i386 + targ_machine=EM_386 + targ_size=32 + targ_big_endian=false + case "$targ" in + i?86-*-freebsd*) + targ_osabi=ELFOSABI_FREEBSD + ;; + esac + ;; +x86_64*) + targ_obj=x86_64 + targ_extra_obj=i386 + targ_machine=EM_X86_64 + targ_size=64 + targ_extra_size=32 + targ_big_endian=false + case "$targ" in + x86_64-*-freebsd*) + targ_osabi=ELFOSABI_FREEBSD + ;; + esac + ;; +tilegx*) + targ_obj=tilegx + targ_machine=EM_TILEGX + targ_size=64 + targ_extra_size=32 + targ_big_endian=false + targ_extra_big_endian=true + ;; +sparc-*) + targ_obj=sparc + targ_machine=EM_SPARC + targ_size=32 + targ_extra_size=64 + targ_big_endian=true + targ_extra_big_endian=false + ;; +sparc64-*) + targ_obj=sparc + targ_machine=EM_SPARCV9 + targ_size=64 + targ_extra_size=32 + targ_big_endian=true + targ_extra_big_endian=false + ;; +powerpc-*) + targ_obj=powerpc + targ_machine=EM_PPC + targ_size=32 + targ_extra_size=64 + targ_big_endian=true + targ_extra_big_endian=false + ;; +powerpcle-*) + targ_obj=powerpc + targ_machine=EM_PPC + targ_size=32 + targ_extra_size=64 + targ_big_endian=false + targ_extra_big_endian=true + ;; +powerpc64-*) + targ_obj=powerpc + targ_machine=EM_PPC64 + targ_size=64 + targ_extra_size=32 + targ_big_endian=true + targ_extra_big_endian=false + ;; +powerpc64le-*) + targ_obj=powerpc + targ_machine=EM_PPC64 + targ_size=64 + targ_extra_size=32 + targ_big_endian=false + targ_extra_big_endian=true + ;; +armeb*-*-*|armbe*-*-*) + targ_obj=arm + targ_extra_obj=arm-reloc-property + targ_machine=EM_ARM + targ_size=32 + targ_big_endian=true + targ_extra_big_endian=false + ;; +arm*-*-*) + targ_obj=arm + targ_extra_obj=arm-reloc-property + targ_machine=EM_ARM + targ_size=32 + targ_big_endian=false + targ_extra_big_endian=true + ;; +*) + targ_obj=UNKNOWN + ;; +esac diff --git a/binutils-2.25/gold/copy-relocs.cc b/binutils-2.25/gold/copy-relocs.cc new file mode 100644 index 00000000..92c5aeaa --- /dev/null +++ b/binutils-2.25/gold/copy-relocs.cc @@ -0,0 +1,258 @@ +// copy-relocs.cc -- handle COPY relocations for gold. + +// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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 "symtab.h" +#include "copy-relocs.h" + +namespace gold +{ + +// Copy_relocs::Copy_reloc_entry methods. + +// Emit the reloc if appropriate. + +template +void +Copy_relocs::Copy_reloc_entry::emit( + Output_data_reloc* reloc_section) +{ + // If the symbol is no longer defined in a dynamic object, then we + // emitted a COPY relocation, and we do not want to emit this + // dynamic relocation. + if (this->sym_->is_from_dynobj()) + reloc_section->add_global_generic(this->sym_, this->reloc_type_, + this->output_section_, this->relobj_, + this->shndx_, this->address_, + this->addend_); +} + +// Copy_relocs methods. + +// Handle a relocation against a symbol which may force us to generate +// a COPY reloc. + +template +void +Copy_relocs::copy_reloc( + Symbol_table* symtab, + Layout* layout, + Sized_symbol* sym, + Sized_relobj_file* object, + unsigned int shndx, + Output_section* output_section, + const Reloc& rel, + Output_data_reloc* reloc_section) +{ + if (this->need_copy_reloc(sym, object, shndx)) + this->make_copy_reloc(symtab, layout, sym, reloc_section); + else + { + // We may not need a COPY relocation. Save this relocation to + // possibly be emitted later. + this->save(sym, object, shndx, output_section, rel); + } +} + +// Return whether we need a COPY reloc for a relocation against SYM. +// The relocation is begin applied to section SHNDX in OBJECT. + +template +bool +Copy_relocs::need_copy_reloc( + Sized_symbol* sym, + Sized_relobj_file* object, + unsigned int shndx) const +{ + if (!parameters->options().copyreloc()) + return false; + + if (sym->symsize() == 0) + return false; + + // If this is a readonly section, then we need a COPY reloc. + // Otherwise we can use a dynamic reloc. Note that calling + // section_flags here can be slow, as the information is not cached; + // fortunately we shouldn't see too many potential COPY relocs. + if ((object->section_flags(shndx) & elfcpp::SHF_WRITE) == 0) + return true; + + return false; +} + +// Emit a COPY relocation for SYM. + +template +void +Copy_relocs::emit_copy_reloc( + Symbol_table* symtab, + Sized_symbol* sym, + Output_data* posd, + off_t offset, + Output_data_reloc* reloc_section) +{ + // Define the symbol as being copied. + symtab->define_with_copy_reloc(sym, posd, offset); + + // Add the COPY relocation to the dynamic reloc section. + reloc_section->add_global_generic(sym, this->copy_reloc_type_, posd, + offset, 0); +} + +// Make a COPY relocation for SYM and emit it. + +template +void +Copy_relocs::make_copy_reloc( + Symbol_table* symtab, + Layout* layout, + Sized_symbol* sym, + Output_data_reloc* reloc_section) +{ + // We should not be here if -z nocopyreloc is given. + gold_assert(parameters->options().copyreloc()); + + typename elfcpp::Elf_types::Elf_WXword symsize = sym->symsize(); + + // There is no defined way to determine the required alignment of + // the symbol. We know that the symbol is defined in a dynamic + // object. We start with the alignment of the section in which it + // is defined; presumably we do not require an alignment larger than + // that. Then we reduce that alignment if the symbol is not aligned + // within the section. + gold_assert(sym->is_from_dynobj()); + bool is_ordinary; + unsigned int shndx = sym->shndx(&is_ordinary); + gold_assert(is_ordinary); + typename elfcpp::Elf_types::Elf_WXword addralign; + + { + // Lock the object so we can read from it. This is only called + // single-threaded from scan_relocs, so it is OK to lock. + // Unfortunately we have no way to pass in a Task token. + const Task* dummy_task = reinterpret_cast(-1); + Object* obj = sym->object(); + Task_lock_obj tl(dummy_task, obj); + addralign = obj->section_addralign(shndx); + } + + typename Sized_symbol::Value_type value = sym->value(); + while ((value & (addralign - 1)) != 0) + addralign >>= 1; + + // Mark the dynamic object as needed for the --as-needed option. + sym->object()->set_is_needed(); + + if (this->dynbss_ == NULL) + { + this->dynbss_ = new Output_data_space(addralign, "** dynbss"); + layout->add_output_section_data(".bss", + elfcpp::SHT_NOBITS, + elfcpp::SHF_ALLOC | elfcpp::SHF_WRITE, + this->dynbss_, ORDER_BSS, false); + } + + Output_data_space* dynbss = this->dynbss_; + + if (addralign > dynbss->addralign()) + dynbss->set_space_alignment(addralign); + + section_size_type dynbss_size = + convert_to_section_size_type(dynbss->current_data_size()); + dynbss_size = align_address(dynbss_size, addralign); + section_size_type offset = dynbss_size; + dynbss->set_current_data_size(dynbss_size + symsize); + + this->emit_copy_reloc(symtab, sym, dynbss, offset, reloc_section); +} + +// Save a relocation to possibly be emitted later. + +template +void +Copy_relocs::save( + Symbol* sym, + Sized_relobj_file* object, + unsigned int shndx, + Output_section* output_section, + const Reloc& rel) +{ + unsigned int reloc_type = elfcpp::elf_r_type(rel.get_r_info()); + typename elfcpp::Elf_types::Elf_Addr addend = + Reloc_types::get_reloc_addend_noerror(&rel); + this->entries_.push_back(Copy_reloc_entry(sym, reloc_type, object, shndx, + output_section, rel.get_r_offset(), + addend)); +} + +// Emit any saved relocs. + +template +void +Copy_relocs::emit( + Output_data_reloc* reloc_section) +{ + for (typename Copy_reloc_entries::iterator p = this->entries_.begin(); + p != this->entries_.end(); + ++p) + p->emit(reloc_section); + + // We no longer need the saved information. + this->entries_.clear(); +} + +// Instantiate the templates we need. + +#ifdef HAVE_TARGET_32_LITTLE +template +class Copy_relocs; + +template +class Copy_relocs; +#endif + +#ifdef HAVE_TARGET_32_BIG +template +class Copy_relocs; + +template +class Copy_relocs; +#endif + +#ifdef HAVE_TARGET_64_LITTLE +template +class Copy_relocs; + +template +class Copy_relocs; +#endif + +#ifdef HAVE_TARGET_64_BIG +template +class Copy_relocs; + +template +class Copy_relocs; +#endif + +} // End namespace gold. diff --git a/binutils-2.25/gold/copy-relocs.h b/binutils-2.25/gold/copy-relocs.h new file mode 100644 index 00000000..d1e2323b --- /dev/null +++ b/binutils-2.25/gold/copy-relocs.h @@ -0,0 +1,156 @@ +// copy-relocs.h -- handle COPY relocations for gold -*- C++ -*- + +// Copyright 2006, 2007, 2008 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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. + +#ifndef GOLD_COPY_RELOCS_H +#define GOLD_COPY_RELOCS_H + +#include "elfcpp.h" +#include "reloc-types.h" +#include "output.h" + +namespace gold +{ + +// This class is used to manage COPY relocations. We try to avoid +// them when possible. A COPY relocation may be required when an +// executable refers to a variable defined in a shared library. COPY +// relocations are problematic because they tie the executable to the +// exact size of the variable in the shared library. We can avoid +// them if all the references to the variable are in a writeable +// section. In that case we can simply use dynamic relocations. +// However, when scanning relocs, we don't know when we see the +// relocation whether we will be forced to use a COPY relocation or +// not. So we have to save the relocation during the reloc scanning, +// and then emit it as a dynamic relocation if necessary. This class +// implements that. It is used by the target specific code. + +// The template parameter SH_TYPE is the type of the reloc section to +// be used for COPY relocs: elfcpp::SHT_REL or elfcpp::SHT_RELA. + +template +class Copy_relocs +{ + private: + typedef typename Reloc_types::Reloc Reloc; + + public: + Copy_relocs(unsigned int copy_reloc_type) + : copy_reloc_type_(copy_reloc_type), dynbss_(NULL), entries_() + { } + + // This is called while scanning relocs if we see a relocation + // against a symbol which may force us to generate a COPY reloc. + // SYM is the symbol. OBJECT is the object whose relocs we are + // scanning. The relocation is being applied to section SHNDX in + // OBJECT. OUTPUT_SECTION is the output section where section SHNDX + // will wind up. REL is the reloc itself. The Output_data_reloc + // section is where the dynamic relocs are put. + void + copy_reloc(Symbol_table*, Layout*, Sized_symbol* sym, + Sized_relobj_file* object, + unsigned int shndx, Output_section* output_section, + const Reloc& rel, + Output_data_reloc*); + + // Return whether there are any saved relocations. + bool + any_saved_relocs() const + { return !this->entries_.empty(); } + + // Emit any saved relocations which turn out to be needed. This is + // called after all the relocs have been scanned. + void + emit(Output_data_reloc*); + + // Emit a COPY reloc. + void + emit_copy_reloc(Symbol_table*, Sized_symbol*, + Output_data*, off_t, + Output_data_reloc*); + + private: + typedef typename elfcpp::Elf_types::Elf_Addr Address; + typedef typename elfcpp::Elf_types::Elf_Addr Addend; + + // This POD class holds the relocations we are saving. We will emit + // these relocations if it turns out that the symbol does not + // require a COPY relocation. + class Copy_reloc_entry + { + public: + Copy_reloc_entry(Symbol* sym, unsigned int reloc_type, + Sized_relobj_file* relobj, + unsigned int shndx, + Output_section* output_section, + Address address, Addend addend) + : sym_(sym), reloc_type_(reloc_type), relobj_(relobj), + shndx_(shndx), output_section_(output_section), + address_(address), addend_(addend) + { } + + // Emit this reloc if appropriate. This is called after we have + // scanned all the relocations, so we know whether we emitted a + // COPY relocation for SYM_. + void + emit(Output_data_reloc*); + + private: + Symbol* sym_; + unsigned int reloc_type_; + Sized_relobj_file* relobj_; + unsigned int shndx_; + Output_section* output_section_; + Address address_; + Addend addend_; + }; + + // A list of relocs to be saved. + typedef std::vector Copy_reloc_entries; + + // Return whether we need a COPY reloc. + bool + need_copy_reloc(Sized_symbol* gsym, + Sized_relobj_file* object, + unsigned int shndx) const; + + // Make a new COPY reloc and emit it. + void + make_copy_reloc(Symbol_table*, Layout*, Sized_symbol*, + Output_data_reloc*); + + // Save a reloc against SYM for possible emission later. + void + save(Symbol*, Sized_relobj_file*, unsigned int shndx, + Output_section*, const Reloc& rel); + + // The target specific relocation type of the COPY relocation. + const unsigned int copy_reloc_type_; + // The dynamic BSS data which goes into the .bss section. This is + // where variables which require COPY relocations are placed. + Output_data_space* dynbss_; + // The list of relocs we are saving. + Copy_reloc_entries entries_; +}; + +} // End namespace gold. + +#endif // !defined(GOLD_COPY_RELOCS_H) diff --git a/binutils-2.25/gold/cref.cc b/binutils-2.25/gold/cref.cc new file mode 100644 index 00000000..ebd48a91 --- /dev/null +++ b/binutils-2.25/gold/cref.cc @@ -0,0 +1,407 @@ +// cref.cc -- cross reference for gold + +// Copyright 2008, 2010 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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 +#include +#include +#include +#include +#include + +#include "object.h" +#include "archive.h" +#include "symtab.h" +#include "cref.h" + +namespace gold +{ + +// Class Cref_inputs. This is used to hold the list of input files +// for cross referencing. + +class Cref_inputs +{ + public: + Cref_inputs() + : objects_(), archives_(), current_(&this->objects_) + { } + + // Add an input object file. + void + add_object(Object* object); + + // Start adding an archive. We support nested archives for future + // flexibility. + void + add_archive_start(Archive*); + + // Finish adding an archive. + void + add_archive_stop(Archive*); + + // Report symbol counts. + void + print_symbol_counts(const Symbol_table*, FILE*) const; + + // Print a cross reference table. + void + print_cref(const Symbol_table*, FILE*) const; + + private: + // A list of input objects. + typedef std::vector Objects; + + // Information we record for an archive. + struct Archive_info + { + // Archive name. + std::string name; + // List of objects included from the archive. + Objects* objects; + // Number of archive members. + size_t member_count; + }; + + // A mapping from the name of an archive to the list of objects in + // that archive. + typedef std::map Archives; + + // For --cref, we build a cross reference table which maps from + // symbols to lists of objects. The symbols are sorted + // alphabetically. + + class Cref_table_compare + { + public: + bool + operator()(const Symbol*, const Symbol*) const; + }; + + typedef std::map Cref_table; + + // Report symbol counts for a list of Objects. + void + print_objects_symbol_counts(const Symbol_table*, FILE*, const Objects*) const; + + // Report symbol counts for an object. + void + print_object_symbol_counts(const Symbol_table*, FILE*, const Object*) const; + + // Gather cross reference information. + void + gather_cref(const Objects*, Cref_table*) const; + + // List of input objects. + Objects objects_; + // List of input archives. This is a mapping from the archive file + // name to the list of objects. + Archives archives_; + // The list to which we are currently adding objects. + Objects* current_; +}; + +// Add an object. + +void +Cref_inputs::add_object(Object* object) +{ + this->current_->push_back(object); +} + +// Start adding an archive. + +void +Cref_inputs::add_archive_start(Archive* archive) +{ + gold_assert(this->current_ == &this->objects_); + if (this->archives_.find(archive->name()) == this->archives_.end()) + { + Archive_info* pai = &this->archives_[archive->name()]; + pai->name = archive->filename(); + pai->objects = new Objects(); + pai->member_count = archive->count_members(); + } + this->current_ = this->archives_[archive->name()].objects; +} + +// Stop adding an archive. + +void +Cref_inputs::add_archive_stop(Archive*) +{ + gold_assert(this->current_ != &this->objects_); + this->current_ = &this->objects_; +} + +// Report symbol counts for an object. + +void +Cref_inputs::print_object_symbol_counts(const Symbol_table* symtab, + FILE* f, + const Object* object) const +{ + size_t defined, used; + object->get_global_symbol_counts(symtab, &defined, &used); + fprintf(f, "symbols %s %zu %zu\n", object->name().c_str(), defined, used); +} + +// Report symbol counts for a list of inputs. + +void +Cref_inputs::print_objects_symbol_counts(const Symbol_table* symtab, + FILE* f, + const Objects* objects) const +{ + for (Objects::const_iterator p = objects->begin(); + p != objects->end(); + ++p) + this->print_object_symbol_counts(symtab, f, *p); +} + +// Print symbol counts. This implements --print-symbol-counts. This +// is intended to be easily read by a program. This outputs a series +// of lines. There are two different types of lines. + +// The first is "symbols FILENAME DEFINED USED". FILENAME is the name +// of an object file included in the link; for an archive, this will +// be ARCHIVEFILENAME(MEMBERNAME). DEFINED is the number of symbols +// which the object file defines. USED is the number of symbols which +// are used in the final output; this is the number of symbols which +// appear in the final output table as having been defined by this +// object. These numbers will be different when weak symbols are +// used, and they will be different for dynamic objects. + +// The second is "archives FILENAME MEMBERS USED". FILENAME is the +// name of an archive file included in the link. MEMBERS is the +// number of members of the archive. USED is the number of archive +// members included in the link. + +void +Cref_inputs::print_symbol_counts(const Symbol_table* symtab, FILE* f) const +{ + this->print_objects_symbol_counts(symtab, f, &this->objects_); + for (Archives::const_iterator p = this->archives_.begin(); + p != this->archives_.end(); + ++p) + { + fprintf(f, "archive %s %zu %zu\n", p->second.name.c_str(), + p->second.member_count, p->second.objects->size()); + this->print_objects_symbol_counts(symtab, f, p->second.objects); + } +} + +// Sort symbols for the cross reference table. + +bool +Cref_inputs::Cref_table_compare::operator()(const Symbol* s1, + const Symbol* s2) const +{ + int i = strcmp(s1->name(), s2->name()); + if (i != 0) + return i < 0; + + if (s1->version() == NULL) + { + if (s2->version() != NULL) + return true; + } + else if (s2->version() == NULL) + return false; + else + { + i = strcmp(s1->version(), s2->version()); + if (i != 0) + return i < 0; + } + + // We should never have two different symbols with the same name and + // version. + if (s1 == s2) + return false; + gold_unreachable(); +} + +// Gather cross reference information from a list of inputs. + +void +Cref_inputs::gather_cref(const Objects* objects, Cref_table* table) const +{ + for (Objects::const_iterator po = objects->begin(); + po != objects->end(); + ++po) + { + const Object::Symbols* symbols = (*po)->get_global_symbols(); + if (symbols == NULL) + continue; + for (Object::Symbols::const_iterator ps = symbols->begin(); + ps != symbols->end(); + ++ps) + { + const Symbol* sym = *ps; + if (sym == NULL) + continue; + Objects* const onull = NULL; + std::pair ins = + table->insert(std::make_pair(sym, onull)); + Cref_table::iterator pc = ins.first; + if (ins.second) + pc->second = new Objects(); + if (sym->source() == Symbol::FROM_OBJECT + && sym->object() == *po + && sym->is_defined()) + pc->second->insert(pc->second->begin(), *po); + else + pc->second->push_back(*po); + } + } +} + +// The column where the file name starts in a cross reference table. + +static const size_t filecol = 50; + +// Print a cross reference table. + +void +Cref_inputs::print_cref(const Symbol_table*, FILE* f) const +{ + Cref_table table; + this->gather_cref(&this->objects_, &table); + for (Archives::const_iterator p = this->archives_.begin(); + p != this->archives_.end(); + ++p) + this->gather_cref(p->second.objects, &table); + + for (Cref_table::const_iterator pc = table.begin(); + pc != table.end(); + ++pc) + { + // If all the objects are dynamic, skip this symbol. + const Symbol* sym = pc->first; + const Objects* objects = pc->second; + Objects::const_iterator po; + for (po = objects->begin(); po != objects->end(); ++po) + if (!(*po)->is_dynamic()) + break; + if (po == objects->end()) + continue; + + std::string s = sym->demangled_name(); + if (sym->version() != NULL) + { + s += '@'; + if (sym->is_default()) + s += '@'; + s += sym->version(); + } + + fputs(s.c_str(), f); + + size_t len = s.length(); + + for (po = objects->begin(); po != objects->end(); ++po) + { + int n = len < filecol ? filecol - len : 1; + fprintf(f, "%*c%s\n", n, ' ', (*po)->name().c_str()); + len = 0; + } + } +} + +// Class Cref. + +// Make sure the Cref_inputs object has been created. + +void +Cref::need_inputs() +{ + if (this->inputs_ == NULL) + this->inputs_ = new Cref_inputs(); +} + +// Add an input object file. + +void +Cref::add_object(Object* object) +{ + this->need_inputs(); + this->inputs_->add_object(object); +} + +// Start adding an archive. + +void +Cref::add_archive_start(Archive* archive) +{ + this->need_inputs(); + this->inputs_->add_archive_start(archive); +} + +// Stop adding an archive. + +void +Cref::add_archive_stop(Archive* archive) +{ + this->inputs_->add_archive_stop(archive); +} + +// Print symbol counts. + +void +Cref::print_symbol_counts(const Symbol_table* symtab) const +{ + if (parameters->options().user_set_print_symbol_counts() + && this->inputs_ != NULL) + { + FILE* f; + if (strcmp(parameters->options().print_symbol_counts(), "-") == 0) + f = stdout; + else + { + f = fopen(parameters->options().print_symbol_counts(), "w"); + if (f == NULL) + gold_error(_("cannot open symbol count file %s: %s"), + parameters->options().print_symbol_counts(), + strerror(errno)); + } + if (f != NULL) + this->inputs_->print_symbol_counts(symtab, f); + } +} + +// Print a cross reference table. + +void +Cref::print_cref(const Symbol_table* symtab, FILE* f) const +{ + fprintf(f, _("\nCross Reference Table\n\n")); + const char* msg = _("Symbol"); + int len = filecol - strlen(msg); + fprintf(f, "%s%*c%s\n", msg, len, ' ', _("File")); + + if (parameters->options().cref() && this->inputs_ != NULL) + this->inputs_->print_cref(symtab, f); +} + +} // End namespace gold. diff --git a/binutils-2.25/gold/cref.h b/binutils-2.25/gold/cref.h new file mode 100644 index 00000000..a40a34af --- /dev/null +++ b/binutils-2.25/gold/cref.h @@ -0,0 +1,79 @@ +// cref.h -- cross reference reports for gold -*- C++ -*- + +// Copyright 2008, 2010 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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. + +#ifndef GOLD_CREF_H +#define GOLD_CREF_H + +#include + +namespace gold +{ + +class Object; +class Archive; +class Cref_inputs; + +// This class collects data for cross reference and other reporting. + +class Cref +{ + public: + Cref() + : inputs_(NULL) + { } + + // Record an input object file. This is called for each object file + // in the order in which it is processed. + void + add_object(Object*); + + // Start recording an input archive. This is called for each + // archive in the order in which it appears on the command line. A + // call to add_archive_start precedes calls to add_object for each + // object included from the archive. + void + add_archive_start(Archive*); + + // Finish recording an input archive. This is called after + // add_object has been called for each object included from the + // archive. + void + add_archive_stop(Archive*); + + // Print symbol counts. + void + print_symbol_counts(const Symbol_table*) const; + + // Print a cross reference table. + void + print_cref(const Symbol_table*, FILE*) const; + + private: + void + need_inputs(); + + Cref_inputs* inputs_; +}; + +} // End namespace gold. + +#endif // !defined(GOLD_CREF_H) diff --git a/binutils-2.25/gold/debug.h b/binutils-2.25/gold/debug.h new file mode 100644 index 00000000..7fdbee78 --- /dev/null +++ b/binutils-2.25/gold/debug.h @@ -0,0 +1,80 @@ +// debug.h -- gold internal debugging support -*- C++ -*- + +// Copyright 2007, 2008 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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. + +#ifndef GOLD_DEBUG_H +#define GOLD_DEBUG_H + +#include + +#include "parameters.h" +#include "errors.h" + +namespace gold +{ + +// The different types of debugging we support. These are bitflags. + +const int DEBUG_TASK = 0x1; +const int DEBUG_SCRIPT = 0x2; +const int DEBUG_FILES = 0x4; +const int DEBUG_RELAXATION = 0x8; +const int DEBUG_INCREMENTAL = 0x10; + +const int DEBUG_ALL = (DEBUG_TASK | DEBUG_SCRIPT | DEBUG_FILES + | DEBUG_RELAXATION | DEBUG_INCREMENTAL); + +// Convert a debug string to the appropriate enum. +inline int +debug_string_to_enum(const char* arg) +{ + static const struct { const char* name; int value; } + debug_options[] = + { + { "task", DEBUG_TASK }, + { "script", DEBUG_SCRIPT }, + { "files", DEBUG_FILES }, + { "relaxation", DEBUG_RELAXATION }, + { "incremental", DEBUG_INCREMENTAL }, + { "all", DEBUG_ALL } + }; + + int retval = 0; + for (size_t i = 0; i < sizeof(debug_options) / sizeof(*debug_options); ++i) + if (strstr(arg, debug_options[i].name)) + retval |= debug_options[i].value; + return retval; +} + +// Print a debug message if TYPE is enabled. This is a macro so that +// we only evaluate the arguments if necessary. + +#define gold_debug(TYPE, FORMAT, ...) \ + do \ + { \ + if (is_debugging_enabled(TYPE)) \ + parameters->errors()->debug(FORMAT, __VA_ARGS__); \ + } \ + while (0) + +} // End namespace gold. + +#endif // !defined(GOLD_DEBUG_H) diff --git a/binutils-2.25/gold/defstd.cc b/binutils-2.25/gold/defstd.cc new file mode 100644 index 00000000..a7a57e44 --- /dev/null +++ b/binutils-2.25/gold/defstd.cc @@ -0,0 +1,274 @@ +// defstd.cc -- define standard symbols for gold. + +// Copyright 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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 "symtab.h" +#include "layout.h" +#include "defstd.h" + +// This is a simple file which defines the standard symbols like +// "_end". + +namespace +{ + +using namespace gold; + +const Define_symbol_in_section in_section[] = +{ + { + "__preinit_array_start", // name + ".preinit_array", // output_section + 0, // value + 0, // size + elfcpp::STT_NOTYPE, // type + elfcpp::STB_GLOBAL, // binding + elfcpp::STV_HIDDEN, // visibility + 0, // nonvis + false, // offset_is_from_end + true // only_if_ref + }, + { + "__preinit_array_end", // name + ".preinit_array", // output_section + 0, // value + 0, // size + elfcpp::STT_NOTYPE, // type + elfcpp::STB_GLOBAL, // binding + elfcpp::STV_HIDDEN, // visibility + 0, // nonvis + true, // offset_is_from_end + true // only_if_ref + }, + { + "__init_array_start", // name + ".init_array", // output_section + 0, // value + 0, // size + elfcpp::STT_NOTYPE, // type + elfcpp::STB_GLOBAL, // binding + elfcpp::STV_HIDDEN, // visibility + 0, // nonvis + false, // offset_is_from_end + true // only_if_ref + }, + { + "__init_array_end", // name + ".init_array", // output_section + 0, // value + 0, // size + elfcpp::STT_NOTYPE, // type + elfcpp::STB_GLOBAL, // binding + elfcpp::STV_HIDDEN, // visibility + 0, // nonvis + true, // offset_is_from_end + true // only_if_ref + }, + { + "__fini_array_start", // name + ".fini_array", // output_section + 0, // value + 0, // size + elfcpp::STT_NOTYPE, // type + elfcpp::STB_GLOBAL, // binding + elfcpp::STV_HIDDEN, // visibility + 0, // nonvis + false, // offset_is_from_end + true // only_if_ref + }, + { + "__fini_array_end", // name + ".fini_array", // output_section + 0, // value + 0, // size + elfcpp::STT_NOTYPE, // type + elfcpp::STB_GLOBAL, // binding + elfcpp::STV_HIDDEN, // visibility + 0, // nonvis + true, // offset_is_from_end + true // only_if_ref + }, + { + "__stack", // name + ".stack", // output_section + 0, // value + 0, // size + elfcpp::STT_NOTYPE, // type + elfcpp::STB_GLOBAL, // binding + elfcpp::STV_DEFAULT, // visibility + 0, // nonvis + false, // offset_is_from_end + true // only_if_ref + }, +}; + +const int in_section_count = sizeof in_section / sizeof in_section[0]; + +const Define_symbol_in_segment in_segment[] = +{ + { + "__executable_start", // name + elfcpp::PT_LOAD, // segment_type + elfcpp::PF(0), // segment_flags_set + elfcpp::PF(0), // segment_flags_clear + 0, // value + 0, // size + elfcpp::STT_NOTYPE, // type + elfcpp::STB_GLOBAL, // binding + elfcpp::STV_DEFAULT, // visibility + 0, // nonvis + Symbol::SEGMENT_START, // offset_from_base + true // only_if_ref + }, + { + "etext", // name + elfcpp::PT_LOAD, // segment_type + elfcpp::PF_X, // segment_flags_set + elfcpp::PF_W, // segment_flags_clear + 0, // value + 0, // size + elfcpp::STT_NOTYPE, // type + elfcpp::STB_GLOBAL, // binding + elfcpp::STV_DEFAULT, // visibility + 0, // nonvis + Symbol::SEGMENT_END, // offset_from_base + true // only_if_ref + }, + { + "_etext", // name + elfcpp::PT_LOAD, // segment_type + elfcpp::PF_X, // segment_flags_set + elfcpp::PF_W, // segment_flags_clear + 0, // value + 0, // size + elfcpp::STT_NOTYPE, // type + elfcpp::STB_GLOBAL, // binding + elfcpp::STV_DEFAULT, // visibility + 0, // nonvis + Symbol::SEGMENT_END, // offset_from_base + true // only_if_ref + }, + { + "__etext", // name + elfcpp::PT_LOAD, // segment_type + elfcpp::PF_X, // segment_flags_set + elfcpp::PF_W, // segment_flags_clear + 0, // value + 0, // size + elfcpp::STT_NOTYPE, // type + elfcpp::STB_GLOBAL, // binding + elfcpp::STV_DEFAULT, // visibility + 0, // nonvis + Symbol::SEGMENT_END, // offset_from_base + true // only_if_ref + }, + { + "_edata", // name + elfcpp::PT_LOAD, // segment_type + elfcpp::PF_W, // segment_flags_set + elfcpp::PF(0), // segment_flags_clear + 0, // value + 0, // size + elfcpp::STT_NOTYPE, // type + elfcpp::STB_GLOBAL, // binding + elfcpp::STV_DEFAULT, // visibility + 0, // nonvis + Symbol::SEGMENT_BSS, // offset_from_base + false // only_if_ref + }, + { + "edata", // name + elfcpp::PT_LOAD, // segment_type + elfcpp::PF_W, // segment_flags_set + elfcpp::PF(0), // segment_flags_clear + 0, // value + 0, // size + elfcpp::STT_NOTYPE, // type + elfcpp::STB_GLOBAL, // binding + elfcpp::STV_DEFAULT, // visibility + 0, // nonvis + Symbol::SEGMENT_BSS, // offset_from_base + true // only_if_ref + }, + { + "__bss_start", // name + elfcpp::PT_LOAD, // segment_type + elfcpp::PF_W, // segment_flags_set + elfcpp::PF(0), // segment_flags_clear + 0, // value + 0, // size + elfcpp::STT_NOTYPE, // type + elfcpp::STB_GLOBAL, // binding + elfcpp::STV_DEFAULT, // visibility + 0, // nonvis + Symbol::SEGMENT_BSS, // offset_from_base + false // only_if_ref + }, + { + "_end", // name + elfcpp::PT_LOAD, // segment_type + elfcpp::PF_W, // segment_flags_set + elfcpp::PF(0), // segment_flags_clear + 0, // value + 0, // size + elfcpp::STT_NOTYPE, // type + elfcpp::STB_GLOBAL, // binding + elfcpp::STV_DEFAULT, // visibility + 0, // nonvis + Symbol::SEGMENT_END, // offset_from_base + false // only_if_ref + }, + { + "end", // name + elfcpp::PT_LOAD, // segment_type + elfcpp::PF_W, // segment_flags_set + elfcpp::PF(0), // segment_flags_clear + 0, // value + 0, // size + elfcpp::STT_NOTYPE, // type + elfcpp::STB_GLOBAL, // binding + elfcpp::STV_DEFAULT, // visibility + 0, // nonvis + Symbol::SEGMENT_END, // offset_from_base + true // only_if_ref + } +}; + +const int in_segment_count = sizeof in_segment / sizeof in_segment[0]; + +} // End anonymous namespace. + +namespace gold +{ + +void +define_standard_symbols(Symbol_table* symtab, const Layout* layout) +{ + bool saw_sections_clause = layout->script_options()->saw_sections_clause(); + symtab->define_symbols(layout, in_section_count, in_section, + saw_sections_clause); + symtab->define_symbols(layout, in_segment_count, in_segment, + saw_sections_clause); +} + +} // End namespace gold. diff --git a/binutils-2.25/gold/defstd.h b/binutils-2.25/gold/defstd.h new file mode 100644 index 00000000..2aea81ce --- /dev/null +++ b/binutils-2.25/gold/defstd.h @@ -0,0 +1,36 @@ +// defstd.h -- define standard symbols for gold -*- C++ -*- + +// Copyright 2006, 2007, 2008 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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. + +#ifndef GOLD_DEFSTD_H +#define GOLD_DEFSTD_H + +#include "symtab.h" + +namespace gold +{ + +extern void +define_standard_symbols(Symbol_table*, const Layout*); + +} // End namespace gold. + +#endif // !defined(GOLD_DEFSTD_H) diff --git a/binutils-2.25/gold/descriptors.cc b/binutils-2.25/gold/descriptors.cc new file mode 100644 index 00000000..b7fbaa61 --- /dev/null +++ b/binutils-2.25/gold/descriptors.cc @@ -0,0 +1,280 @@ +// descriptors.cc -- manage file descriptors for gold + +// Copyright 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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 +#include +#include +#include +#include + +#include "parameters.h" +#include "options.h" +#include "gold-threads.h" +#include "descriptors.h" +#include "binary-io.h" + +// O_CLOEXEC is only available on newer systems. +#ifndef O_CLOEXEC +#define O_CLOEXEC 0 +#endif + +// Very old systems may not define FD_CLOEXEC. +#ifndef FD_CLOEXEC +#define FD_CLOEXEC 1 +#endif + +static inline void +set_close_on_exec(int fd ATTRIBUTE_UNUSED) +{ +// Mingw does not define F_SETFD. +#ifdef F_SETFD + fcntl(fd, F_SETFD, FD_CLOEXEC); +#endif +} + +namespace gold +{ + +// Class Descriptors. + +// The default for limit_ is meant to simply be large. It gets +// adjusted downward if we run out of file descriptors. + +Descriptors::Descriptors() + : lock_(NULL), initialize_lock_(&this->lock_), open_descriptors_(), + stack_top_(-1), current_(0), limit_(8192 - 16) +{ + this->open_descriptors_.reserve(128); +} + +// Open a file. + +int +Descriptors::open(int descriptor, const char* name, int flags, int mode) +{ + // We don't initialize this until we are called, because we can't + // initialize a Lock until we have parsed the options to find out + // whether we are running with threads. We can be called before + // options are valid when reading a linker script. + bool lock_initialized = this->initialize_lock_.initialize(); + + gold_assert(lock_initialized || descriptor < 0); + + if (descriptor >= 0) + { + Hold_lock hl(*this->lock_); + + gold_assert(static_cast(descriptor) + < this->open_descriptors_.size()); + Open_descriptor* pod = &this->open_descriptors_[descriptor]; + if (pod->name == name + || (pod->name != NULL && strcmp(pod->name, name) == 0)) + { + gold_assert(!pod->inuse); + pod->inuse = true; + if (descriptor == this->stack_top_) + { + this->stack_top_ = pod->stack_next; + pod->stack_next = -1; + pod->is_on_stack = false; + } + return descriptor; + } + } + + while (true) + { + // We always want to set the close-on-exec flag; we don't + // require callers to pass it. + flags |= O_CLOEXEC; + + // Always open the file as a binary file. + flags |= O_BINARY; + + int new_descriptor = ::open(name, flags, mode); + if (new_descriptor < 0 + && errno != ENFILE + && errno != EMFILE) + { + if (descriptor >= 0 && errno == ENOENT) + { + { + Hold_lock hl(*this->lock_); + + gold_error(_("file %s was removed during the link"), name); + } + + errno = ENOENT; + } + + return new_descriptor; + } + + if (new_descriptor >= 0) + { + // If we have any plugins, we really do need to set the + // close-on-exec flag, even if O_CLOEXEC is not defined. + // FIXME: In some cases O_CLOEXEC may be defined in the + // header file but not supported by the kernel. + // Unfortunately there doesn't seem to be any obvious way to + // detect that, as unknown flags passed to open are ignored. + if (O_CLOEXEC == 0 + && parameters->options_valid() + && parameters->options().has_plugins()) + set_close_on_exec(new_descriptor); + + { + Hold_optional_lock hl(this->lock_); + + if (static_cast(new_descriptor) + >= this->open_descriptors_.size()) + this->open_descriptors_.resize(new_descriptor + 64); + + Open_descriptor* pod = &this->open_descriptors_[new_descriptor]; + pod->name = name; + pod->stack_next = -1; + pod->inuse = true; + pod->is_write = (flags & O_ACCMODE) != O_RDONLY; + pod->is_on_stack = false; + + ++this->current_; + if (this->current_ >= this->limit_) + this->close_some_descriptor(); + + return new_descriptor; + } + } + + // We ran out of file descriptors. + { + Hold_optional_lock hl(this->lock_); + + this->limit_ = this->current_ - 16; + if (this->limit_ < 8) + this->limit_ = 8; + if (!this->close_some_descriptor()) + gold_fatal(_("out of file descriptors and couldn't close any")); + } + } +} + +// Release a descriptor. + +void +Descriptors::release(int descriptor, bool permanent) +{ + Hold_optional_lock hl(this->lock_); + + gold_assert(descriptor >= 0 + && (static_cast(descriptor) + < this->open_descriptors_.size())); + Open_descriptor* pod = &this->open_descriptors_[descriptor]; + + if (permanent + || (this->current_ > this->limit_ && !pod->is_write)) + { + if (::close(descriptor) < 0) + gold_warning(_("while closing %s: %s"), pod->name, strerror(errno)); + pod->name = NULL; + --this->current_; + } + else + { + pod->inuse = false; + if (!pod->is_write && !pod->is_on_stack) + { + pod->stack_next = this->stack_top_; + this->stack_top_ = descriptor; + pod->is_on_stack = true; + } + } +} + +// Close some descriptor. The lock is held when this is called. We +// close the descriptor on the top of the free stack. Note that this +// is the opposite of an LRU algorithm--we close the most recently +// used descriptor. That is because the linker tends to cycle through +// all the files; after we release a file, we are unlikely to need it +// again until we have looked at all the other files. Return true if +// we closed a descriptor. + +bool +Descriptors::close_some_descriptor() +{ + int last = -1; + int i = this->stack_top_; + while (i >= 0) + { + gold_assert(static_cast(i) < this->open_descriptors_.size()); + Open_descriptor* pod = &this->open_descriptors_[i]; + if (!pod->inuse && !pod->is_write) + { + if (::close(i) < 0) + gold_warning(_("while closing %s: %s"), pod->name, strerror(errno)); + --this->current_; + pod->name = NULL; + if (last < 0) + this->stack_top_ = pod->stack_next; + else + this->open_descriptors_[last].stack_next = pod->stack_next; + pod->stack_next = -1; + pod->is_on_stack = false; + return true; + } + last = i; + i = pod->stack_next; + } + + // We couldn't find any descriptors to close. This is weird but not + // necessarily an error. + return false; +} + +// Close all the descriptors open for reading. + +void +Descriptors::close_all() +{ + Hold_optional_lock hl(this->lock_); + + for (size_t i = 0; i < this->open_descriptors_.size(); i++) + { + Open_descriptor* pod = &this->open_descriptors_[i]; + if (pod->name != NULL && !pod->inuse && !pod->is_write) + { + if (::close(i) < 0) + gold_warning(_("while closing %s: %s"), pod->name, strerror(errno)); + pod->name = NULL; + pod->stack_next = -1; + pod->is_on_stack = false; + } + } + this->stack_top_ = -1; +} + +// The single global variable which manages descriptors. + +Descriptors descriptors; + +} // End namespace gold. diff --git a/binutils-2.25/gold/descriptors.h b/binutils-2.25/gold/descriptors.h new file mode 100644 index 00000000..985f8045 --- /dev/null +++ b/binutils-2.25/gold/descriptors.h @@ -0,0 +1,117 @@ +// descriptors.h -- manage file descriptors for gold -*- C++ -*- + +// Copyright 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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. + +#ifndef GOLD_DESCRIPTORS_H +#define GOLD_DESCRIPTORS_H + +#include + +#include "gold-threads.h" + +namespace gold +{ + +// This class manages file descriptors for gold. + +class Descriptors +{ + public: + Descriptors(); + + // Get a file descriptor for a file. The DESCRIPTOR parameter is + // the descriptor the last time the file was used; this will be -1 + // if this is the first time the file is being opened. The NAME, + // FLAGS, and MODE parameters are as for ::open. NAME must be in + // permanent storage. This returns the descriptor to use, which may + // or may not be the same as DESCRIPTOR. If there is an error + // opening the file, this will return -1 with errno set + // appropriately. + int + open(int descriptor, const char* name, int flags, int mode = 0); + + // Release the file descriptor DESCRIPTOR. If PERMANENT is true, it + // will be closed, and the caller may not reopen it. If PERMANENT + // is false this doesn't necessarily close the descriptor, but it + // makes it available to be closed; the descriptor must not be used + // again except as an argument to Descriptor::open. + void + release(int descriptor, bool permanent); + + // Close all the descriptors open for reading. + void + close_all(); + + private: + // Information kept for a descriptor. + struct Open_descriptor + { + // File name currently associated with descriptor. This is empty + // if none. + const char* name; + // Index of next descriptor on stack of released descriptors. + int stack_next; + // Whether the descriptor is currently in use. + bool inuse; + // Whether this is a write descriptor. + bool is_write; + // Whether the descriptor is on the stack. + bool is_on_stack; + }; + + bool + close_some_descriptor(); + + // We need to lock before accessing any fields. + Lock* lock_; + // Used to initialize the lock_ field exactly once. + Initialize_lock initialize_lock_; + // Information for descriptors. + std::vector open_descriptors_; + // Top of stack. + int stack_top_; + // The current number of file descriptors open. + int current_; + // The maximum number of file descriptors we open. + int limit_; +}; + +// File descriptors are a centralized data structure, and we use a +// global variable rather than passing the data structure into every +// routine that does file I/O. + +extern Descriptors descriptors; + +inline int +open_descriptor(int descriptor, const char* name, int flags, int mode = 0) +{ return descriptors.open(descriptor, name, flags, mode); } + +inline void +release_descriptor(int descriptor, bool permanent) +{ descriptors.release(descriptor, permanent); } + +inline void +close_all_descriptors() +{ descriptors.close_all(); } + +} // End namespace gold. + +#endif // !defined(GOLD_DESCRIPTORS_H) diff --git a/binutils-2.25/gold/dirsearch.cc b/binutils-2.25/gold/dirsearch.cc new file mode 100644 index 00000000..a6114a44 --- /dev/null +++ b/binutils-2.25/gold/dirsearch.cc @@ -0,0 +1,305 @@ +// dirsearch.cc -- directory searching for gold + +// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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 +#include +#include +#include +#include + +#include "debug.h" +#include "gold-threads.h" +#include "options.h" +#include "workqueue.h" +#include "dirsearch.h" + +namespace +{ + +// Read all the files in a directory. + +class Dir_cache +{ + public: + Dir_cache(const char* dirname) + : dirname_(dirname), files_() + { } + + // Read the files in the directory. + void read_files(); + + // Return whether a file (a base name) is present in the directory. + bool find(const std::string&) const; + + private: + // We can not copy this class. + Dir_cache(const Dir_cache&); + Dir_cache& operator=(const Dir_cache&); + + const char* dirname_; + Unordered_set files_; +}; + +void +Dir_cache::read_files() +{ + DIR* d = opendir(this->dirname_); + if (d == NULL) + { + // We ignore directories which do not exist or are actually file + // names. + if (errno != ENOENT && errno != ENOTDIR) + gold::gold_error(_("%s: can not read directory: %s"), + this->dirname_, strerror(errno)); + return; + } + + dirent* de; + while ((de = readdir(d)) != NULL) + this->files_.insert(std::string(de->d_name)); + + if (closedir(d) != 0) + gold::gold_warning("%s: closedir failed: %s", this->dirname_, + strerror(errno)); +} + +bool +Dir_cache::find(const std::string& basename) const +{ + return this->files_.find(basename) != this->files_.end(); +} + +// A mapping from directory names to caches. A lock permits +// concurrent update. There is no lock for read operations--some +// other mechanism must be used to prevent reads from conflicting with +// writes. + +class Dir_caches +{ + public: + Dir_caches() + : lock_(), caches_() + { } + + ~Dir_caches(); + + // Add a cache for a directory. + void add(const char*); + + // Look up a directory in the cache. This much be locked against + // calls to Add. + Dir_cache* lookup(const char*) const; + + private: + // We can not copy this class. + Dir_caches(const Dir_caches&); + Dir_caches& operator=(const Dir_caches&); + + typedef Unordered_map Cache_hash; + + gold::Lock lock_; + Cache_hash caches_; +}; + +Dir_caches::~Dir_caches() +{ + for (Cache_hash::iterator p = this->caches_.begin(); + p != this->caches_.end(); + ++p) + delete p->second; +} + +void +Dir_caches::add(const char* dirname) +{ + { + gold::Hold_lock hl(this->lock_); + if (this->lookup(dirname) != NULL) + return; + } + + Dir_cache* cache = new Dir_cache(dirname); + + cache->read_files(); + + { + gold::Hold_lock hl(this->lock_); + + std::pair v(dirname, cache); + std::pair p = this->caches_.insert(v); + gold_assert(p.second); + } +} + +Dir_cache* +Dir_caches::lookup(const char* dirname) const +{ + Cache_hash::const_iterator p = this->caches_.find(dirname); + if (p == this->caches_.end()) + return NULL; + return p->second; +} + +// The caches. + +Dir_caches* caches; + +// A Task to read the directory. + +class Dir_cache_task : public gold::Task +{ + public: + Dir_cache_task(const char* dir, gold::Task_token& token) + : dir_(dir), token_(token) + { } + + gold::Task_token* + is_runnable(); + + void + locks(gold::Task_locker*); + + void + run(gold::Workqueue*); + + std::string + get_name() const + { return std::string("Dir_cache_task ") + this->dir_; } + + private: + const char* dir_; + gold::Task_token& token_; +}; + +// We can always run the task to read the directory. + +gold::Task_token* +Dir_cache_task::is_runnable() +{ + return NULL; +} + +// Return the locks to hold. We use a blocker lock to prevent file +// lookups from starting until the directory contents have been read. + +void +Dir_cache_task::locks(gold::Task_locker* tl) +{ + tl->add(this, &this->token_); +} + +// Run the task--read the directory contents. + +void +Dir_cache_task::run(gold::Workqueue*) +{ + caches->add(this->dir_); +} + +} + +namespace gold +{ + +// Initialize. + +void +Dirsearch::initialize(Workqueue* workqueue, + const General_options::Dir_list* directories) +{ + gold_assert(caches == NULL); + caches = new Dir_caches; + this->directories_ = directories; + this->token_.add_blockers(directories->size()); + for (General_options::Dir_list::const_iterator p = directories->begin(); + p != directories->end(); + ++p) + workqueue->queue(new Dir_cache_task(p->name().c_str(), this->token_)); +} + +// Search for a file. NOTE: we only log failed file-lookup attempts +// here. Successfully lookups will eventually get logged in +// File_read::open. + +std::string +Dirsearch::find(const std::vector& names, + bool* is_in_sysroot, int* pindex, + std::string *found_name) const +{ + gold_assert(!this->token_.is_blocked()); + gold_assert(*pindex >= 0); + + for (unsigned int i = static_cast(*pindex); + i < this->directories_->size(); + ++i) + { + const Search_directory* p = &this->directories_->at(i); + Dir_cache* pdc = caches->lookup(p->name().c_str()); + gold_assert(pdc != NULL); + for (std::vector::const_iterator n = names.begin(); + n != names.end(); + ++n) + { + if (pdc->find(*n)) + { + *is_in_sysroot = p->is_in_sysroot(); + *pindex = i; + *found_name = *n; + return p->name() + '/' + *n; + } + else + gold_debug(DEBUG_FILES, "Attempt to open %s/%s failed", + p->name().c_str(), (*n).c_str()); + } + } + + *pindex = -2; + return std::string(); +} + +// Search for a file in a directory list. This is a low-level function and +// therefore can be used before options and parameters are set. + +std::string +Dirsearch::find_file_in_dir_list(const std::string& name, + const General_options::Dir_list& directories, + const std::string& extra_search_dir) +{ + struct stat buf; + std::string extra_name = extra_search_dir + '/' + name; + + if (stat(extra_name.c_str(), &buf) == 0) + return extra_name; + for (General_options::Dir_list::const_iterator dir = directories.begin(); + dir != directories.end(); + ++dir) + { + std::string full_name = dir->name() + '/' + name; + if (stat(full_name.c_str(), &buf) == 0) + return full_name; + } + return name; +} + +} // End namespace gold. diff --git a/binutils-2.25/gold/dirsearch.h b/binutils-2.25/gold/dirsearch.h new file mode 100644 index 00000000..ebc0b5b3 --- /dev/null +++ b/binutils-2.25/gold/dirsearch.h @@ -0,0 +1,90 @@ +// dirsearch.h -- directory searching for gold -*- C++ -*- + +// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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. + +#ifndef GOLD_DIRSEARCH_H +#define GOLD_DIRSEARCH_H + +#include +#include + +#include "options.h" +#include "token.h" + +namespace gold +{ + +class General_options; +class Workqueue; + +// A simple interface to manage directories to be searched for +// libraries. + +class Dirsearch +{ + public: + Dirsearch() + : directories_(NULL), token_(true) + { } + + // Set the list of directories to search. + void + initialize(Workqueue*, const General_options::Dir_list*); + + // Search for a file, giving one or two names to search for (the + // second one may be empty). Return a full path name for the file, + // or the empty string if it could not be found. This may only be + // called if the token is not blocked. Set *IS_IN_SYSROOT if the + // file was found in a directory which is in the sysroot. *PINDEX + // should be set to zero the first time this is called; it will be + // updated with the index of the directory where the file is found, + // and that value plus one may be used to find the next file with + // the same name(s). + std::string + find(const std::vector& names, bool* is_in_sysroot, + int* pindex, std::string *found_name) const; + + // Return the blocker token which controls access. + Task_token* + token() + { return &this->token_; } + + // Search for a file in a directory list. This is a low-level function and + // therefore can be used before options and parameters are set. + static std::string + find_file_in_dir_list(const std::string& name, + const General_options::Dir_list& directories, + const std::string& extra_search_dir); + + private: + // We can not copy this class. + Dirsearch(const Dirsearch&); + Dirsearch& operator=(const Dirsearch&); + + // Directories to search. + const General_options::Dir_list* directories_; + // Blocker token to control access from tasks. + Task_token token_; +}; + +} // End namespace gold. + +#endif // !defined(GOLD_DIRSEARCH_H) diff --git a/binutils-2.25/gold/dwarf_reader.cc b/binutils-2.25/gold/dwarf_reader.cc new file mode 100644 index 00000000..fb2a1525 --- /dev/null +++ b/binutils-2.25/gold/dwarf_reader.cc @@ -0,0 +1,2373 @@ +// dwarf_reader.cc -- parse dwarf2/3 debug information + +// Copyright 2007, 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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 +#include + +#include "elfcpp_swap.h" +#include "dwarf.h" +#include "object.h" +#include "reloc.h" +#include "dwarf_reader.h" +#include "int_encoding.h" +#include "compressed_output.h" + +namespace gold { + +// Class Sized_elf_reloc_mapper + +// Initialize the relocation tracker for section RELOC_SHNDX. + +template +bool +Sized_elf_reloc_mapper::do_initialize( + unsigned int reloc_shndx, unsigned int reloc_type) +{ + this->reloc_type_ = reloc_type; + return this->track_relocs_.initialize(this->object_, reloc_shndx, + reloc_type); +} + +// Looks in the symtab to see what section a symbol is in. + +template +unsigned int +Sized_elf_reloc_mapper::symbol_section( + unsigned int symndx, Address* value, bool* is_ordinary) +{ + const int symsize = elfcpp::Elf_sizes::sym_size; + gold_assert(static_cast((symndx + 1) * symsize) <= this->symtab_size_); + elfcpp::Sym elfsym(this->symtab_ + symndx * symsize); + *value = elfsym.get_st_value(); + return this->object_->adjust_sym_shndx(symndx, elfsym.get_st_shndx(), + is_ordinary); +} + +// Return the section index and offset within the section of +// the target of the relocation for RELOC_OFFSET. + +template +unsigned int +Sized_elf_reloc_mapper::do_get_reloc_target( + off_t reloc_offset, off_t* target_offset) +{ + this->track_relocs_.advance(reloc_offset); + if (reloc_offset != this->track_relocs_.next_offset()) + return 0; + unsigned int symndx = this->track_relocs_.next_symndx(); + typename elfcpp::Elf_types::Elf_Addr value; + bool is_ordinary; + unsigned int target_shndx = this->symbol_section(symndx, &value, + &is_ordinary); + if (!is_ordinary) + return 0; + if (this->reloc_type_ == elfcpp::SHT_RELA) + value += this->track_relocs_.next_addend(); + *target_offset = value; + return target_shndx; +} + +static inline Elf_reloc_mapper* +make_elf_reloc_mapper(Relobj* object, const unsigned char* symtab, + off_t symtab_size) +{ + if (object->elfsize() == 32) + { + if (object->is_big_endian()) + { +#ifdef HAVE_TARGET_32_BIG + return new Sized_elf_reloc_mapper<32, true>(object, symtab, + symtab_size); +#else + gold_unreachable(); +#endif + } + else + { +#ifdef HAVE_TARGET_32_LITTLE + return new Sized_elf_reloc_mapper<32, false>(object, symtab, + symtab_size); +#else + gold_unreachable(); +#endif + } + } + else if (object->elfsize() == 64) + { + if (object->is_big_endian()) + { +#ifdef HAVE_TARGET_64_BIG + return new Sized_elf_reloc_mapper<64, true>(object, symtab, + symtab_size); +#else + gold_unreachable(); +#endif + } + else + { +#ifdef HAVE_TARGET_64_LITTLE + return new Sized_elf_reloc_mapper<64, false>(object, symtab, + symtab_size); +#else + gold_unreachable(); +#endif + } + } + else + gold_unreachable(); +} + +// class Dwarf_abbrev_table + +void +Dwarf_abbrev_table::clear_abbrev_codes() +{ + for (unsigned int code = 0; code < this->low_abbrev_code_max_; ++code) + { + if (this->low_abbrev_codes_[code] != NULL) + { + delete this->low_abbrev_codes_[code]; + this->low_abbrev_codes_[code] = NULL; + } + } + for (Abbrev_code_table::iterator it = this->high_abbrev_codes_.begin(); + it != this->high_abbrev_codes_.end(); + ++it) + { + if (it->second != NULL) + delete it->second; + } + this->high_abbrev_codes_.clear(); +} + +// Read the abbrev table from an object file. + +bool +Dwarf_abbrev_table::do_read_abbrevs( + Relobj* object, + unsigned int abbrev_shndx, + off_t abbrev_offset) +{ + this->clear_abbrev_codes(); + + // If we don't have relocations, abbrev_shndx will be 0, and + // we'll have to hunt for the .debug_abbrev section. + if (abbrev_shndx == 0 && this->abbrev_shndx_ > 0) + abbrev_shndx = this->abbrev_shndx_; + else if (abbrev_shndx == 0) + { + for (unsigned int i = 1; i < object->shnum(); ++i) + { + std::string name = object->section_name(i); + if (name == ".debug_abbrev") + { + abbrev_shndx = i; + // Correct the offset. For incremental update links, we have a + // relocated offset that is relative to the output section, but + // here we need an offset relative to the input section. + abbrev_offset -= object->output_section_offset(i); + break; + } + } + if (abbrev_shndx == 0) + return false; + } + + // Get the section contents and decompress if necessary. + if (abbrev_shndx != this->abbrev_shndx_) + { + if (this->owns_buffer_ && this->buffer_ != NULL) + { + delete[] this->buffer_; + this->owns_buffer_ = false; + } + + section_size_type buffer_size; + this->buffer_ = + object->decompressed_section_contents(abbrev_shndx, + &buffer_size, + &this->owns_buffer_); + this->buffer_end_ = this->buffer_ + buffer_size; + this->abbrev_shndx_ = abbrev_shndx; + } + + this->buffer_pos_ = this->buffer_ + abbrev_offset; + return true; +} + +// Lookup the abbrev code entry for CODE. This function is called +// only when the abbrev code is not in the direct lookup table. +// It may be in the hash table, it may not have been read yet, +// or it may not exist in the abbrev table. + +const Dwarf_abbrev_table::Abbrev_code* +Dwarf_abbrev_table::do_get_abbrev(unsigned int code) +{ + // See if the abbrev code is already in the hash table. + Abbrev_code_table::const_iterator it = this->high_abbrev_codes_.find(code); + if (it != this->high_abbrev_codes_.end()) + return it->second; + + // Read and store abbrev code definitions until we find the + // one we're looking for. + for (;;) + { + // Read the abbrev code. A zero here indicates the end of the + // abbrev table. + size_t len; + if (this->buffer_pos_ >= this->buffer_end_) + return NULL; + uint64_t nextcode = read_unsigned_LEB_128(this->buffer_pos_, &len); + if (nextcode == 0) + { + this->buffer_pos_ = this->buffer_end_; + return NULL; + } + this->buffer_pos_ += len; + + // Read the tag. + if (this->buffer_pos_ >= this->buffer_end_) + return NULL; + uint64_t tag = read_unsigned_LEB_128(this->buffer_pos_, &len); + this->buffer_pos_ += len; + + // Read the has_children flag. + if (this->buffer_pos_ >= this->buffer_end_) + return NULL; + bool has_children = *this->buffer_pos_ == elfcpp::DW_CHILDREN_yes; + this->buffer_pos_ += 1; + + // Read the list of (attribute, form) pairs. + Abbrev_code* entry = new Abbrev_code(tag, has_children); + for (;;) + { + // Read the attribute. + if (this->buffer_pos_ >= this->buffer_end_) + return NULL; + uint64_t attr = read_unsigned_LEB_128(this->buffer_pos_, &len); + this->buffer_pos_ += len; + + // Read the form. + if (this->buffer_pos_ >= this->buffer_end_) + return NULL; + uint64_t form = read_unsigned_LEB_128(this->buffer_pos_, &len); + this->buffer_pos_ += len; + + // A (0,0) pair terminates the list. + if (attr == 0 && form == 0) + break; + + if (attr == elfcpp::DW_AT_sibling) + entry->has_sibling_attribute = true; + + entry->add_attribute(attr, form); + } + + this->store_abbrev(nextcode, entry); + if (nextcode == code) + return entry; + } + + return NULL; +} + +// class Dwarf_ranges_table + +// Read the ranges table from an object file. + +bool +Dwarf_ranges_table::read_ranges_table( + Relobj* object, + const unsigned char* symtab, + off_t symtab_size, + unsigned int ranges_shndx) +{ + // If we've already read this abbrev table, return immediately. + if (this->ranges_shndx_ > 0 + && this->ranges_shndx_ == ranges_shndx) + return true; + + // If we don't have relocations, ranges_shndx will be 0, and + // we'll have to hunt for the .debug_ranges section. + if (ranges_shndx == 0 && this->ranges_shndx_ > 0) + ranges_shndx = this->ranges_shndx_; + else if (ranges_shndx == 0) + { + for (unsigned int i = 1; i < object->shnum(); ++i) + { + std::string name = object->section_name(i); + if (name == ".debug_ranges") + { + ranges_shndx = i; + this->output_section_offset_ = object->output_section_offset(i); + break; + } + } + if (ranges_shndx == 0) + return false; + } + + // Get the section contents and decompress if necessary. + if (ranges_shndx != this->ranges_shndx_) + { + if (this->owns_ranges_buffer_ && this->ranges_buffer_ != NULL) + { + delete[] this->ranges_buffer_; + this->owns_ranges_buffer_ = false; + } + + section_size_type buffer_size; + this->ranges_buffer_ = + object->decompressed_section_contents(ranges_shndx, + &buffer_size, + &this->owns_ranges_buffer_); + this->ranges_buffer_end_ = this->ranges_buffer_ + buffer_size; + this->ranges_shndx_ = ranges_shndx; + } + + if (this->ranges_reloc_mapper_ != NULL) + { + delete this->ranges_reloc_mapper_; + this->ranges_reloc_mapper_ = NULL; + } + + // For incremental objects, we have no relocations. + if (object->is_incremental()) + return true; + + // Find the relocation section for ".debug_ranges". + unsigned int reloc_shndx = 0; + unsigned int reloc_type = 0; + for (unsigned int i = 0; i < object->shnum(); ++i) + { + reloc_type = object->section_type(i); + if ((reloc_type == elfcpp::SHT_REL + || reloc_type == elfcpp::SHT_RELA) + && object->section_info(i) == ranges_shndx) + { + reloc_shndx = i; + break; + } + } + + this->ranges_reloc_mapper_ = make_elf_reloc_mapper(object, symtab, + symtab_size); + this->ranges_reloc_mapper_->initialize(reloc_shndx, reloc_type); + this->reloc_type_ = reloc_type; + + return true; +} + +// Read a range list from section RANGES_SHNDX at offset RANGES_OFFSET. + +Dwarf_range_list* +Dwarf_ranges_table::read_range_list( + Relobj* object, + const unsigned char* symtab, + off_t symtab_size, + unsigned int addr_size, + unsigned int ranges_shndx, + off_t offset) +{ + Dwarf_range_list* ranges; + + if (!this->read_ranges_table(object, symtab, symtab_size, ranges_shndx)) + return NULL; + + // Correct the offset. For incremental update links, we have a + // relocated offset that is relative to the output section, but + // here we need an offset relative to the input section. + offset -= this->output_section_offset_; + + // Read the range list at OFFSET. + ranges = new Dwarf_range_list(); + off_t base = 0; + for (; + this->ranges_buffer_ + offset < this->ranges_buffer_end_; + offset += 2 * addr_size) + { + off_t start; + off_t end; + + // Read the raw contents of the section. + if (addr_size == 4) + { + start = this->dwinfo_->read_from_pointer<32>(this->ranges_buffer_ + + offset); + end = this->dwinfo_->read_from_pointer<32>(this->ranges_buffer_ + + offset + 4); + } + else + { + start = this->dwinfo_->read_from_pointer<64>(this->ranges_buffer_ + + offset); + end = this->dwinfo_->read_from_pointer<64>(this->ranges_buffer_ + + offset + 8); + } + + // Check for relocations and adjust the values. + unsigned int shndx1 = 0; + unsigned int shndx2 = 0; + if (this->ranges_reloc_mapper_ != NULL) + { + shndx1 = this->lookup_reloc(offset, &start); + shndx2 = this->lookup_reloc(offset + addr_size, &end); + } + + // End of list is marked by a pair of zeroes. + if (shndx1 == 0 && start == 0 && end == 0) + break; + + // A "base address selection entry" is identified by + // 0xffffffff for the first value of the pair. The second + // value is used as a base for subsequent range list entries. + if (shndx1 == 0 && start == -1) + base = end; + else if (shndx1 == shndx2) + { + if (shndx1 == 0 || object->is_section_included(shndx1)) + ranges->add(shndx1, base + start, base + end); + } + else + gold_warning(_("%s: DWARF info may be corrupt; offsets in a " + "range list entry are in different sections"), + object->name().c_str()); + } + + return ranges; +} + +// Look for a relocation at offset OFF in the range table, +// and return the section index and offset of the target. + +unsigned int +Dwarf_ranges_table::lookup_reloc(off_t off, off_t* target_off) +{ + off_t value; + unsigned int shndx = + this->ranges_reloc_mapper_->get_reloc_target(off, &value); + if (shndx == 0) + return 0; + if (this->reloc_type_ == elfcpp::SHT_REL) + *target_off += value; + else + *target_off = value; + return shndx; +} + +// class Dwarf_pubnames_table + +// Read the pubnames section from the object file. + +bool +Dwarf_pubnames_table::read_section(Relobj* object, const unsigned char* symtab, + off_t symtab_size) +{ + section_size_type buffer_size; + unsigned int shndx = 0; + + // Find the .debug_pubnames/pubtypes section. + const char* name = (this->is_pubtypes_ + ? ".debug_pubtypes" + : ".debug_pubnames"); + for (unsigned int i = 1; i < object->shnum(); ++i) + { + if (object->section_name(i) == name) + { + shndx = i; + this->output_section_offset_ = object->output_section_offset(i); + break; + } + } + if (shndx == 0) + return false; + + + this->buffer_ = object->decompressed_section_contents(shndx, + &buffer_size, + &this->owns_buffer_); + if (this->buffer_ == NULL) + return false; + this->buffer_end_ = this->buffer_ + buffer_size; + + // For incremental objects, we have no relocations. + if (object->is_incremental()) + return true; + + // Find the relocation section + unsigned int reloc_shndx = 0; + unsigned int reloc_type = 0; + for (unsigned int i = 0; i < object->shnum(); ++i) + { + reloc_type = object->section_type(i); + if ((reloc_type == elfcpp::SHT_REL + || reloc_type == elfcpp::SHT_RELA) + && object->section_info(i) == shndx) + { + reloc_shndx = i; + break; + } + } + + this->reloc_mapper_ = make_elf_reloc_mapper(object, symtab, symtab_size); + this->reloc_mapper_->initialize(reloc_shndx, reloc_type); + this->reloc_type_ = reloc_type; + + return true; +} + +// Read the header for the set at OFFSET. + +bool +Dwarf_pubnames_table::read_header(off_t offset) +{ + // Make sure we have actually read the section. + gold_assert(this->buffer_ != NULL); + + // Correct the offset. For incremental update links, we have a + // relocated offset that is relative to the output section, but + // here we need an offset relative to the input section. + offset -= this->output_section_offset_; + + if (offset < 0 || offset + 14 >= this->buffer_end_ - this->buffer_) + return false; + + const unsigned char* pinfo = this->buffer_ + offset; + + // Read the unit_length field. + uint64_t unit_length = this->dwinfo_->read_from_pointer<32>(pinfo); + pinfo += 4; + if (unit_length == 0xffffffff) + { + unit_length = this->dwinfo_->read_from_pointer<64>(pinfo); + this->unit_length_ = unit_length + 12; + pinfo += 8; + this->offset_size_ = 8; + } + else + { + this->unit_length_ = unit_length + 4; + this->offset_size_ = 4; + } + + // Check the version. + unsigned int version = this->dwinfo_->read_from_pointer<16>(pinfo); + pinfo += 2; + if (version != 2) + return false; + + this->reloc_mapper_->get_reloc_target(pinfo - this->buffer_, + &this->cu_offset_); + + // Skip the debug_info_offset and debug_info_size fields. + pinfo += 2 * this->offset_size_; + + if (pinfo >= this->buffer_end_) + return false; + + this->pinfo_ = pinfo; + return true; +} + +// Read the next name from the set. + +const char* +Dwarf_pubnames_table::next_name() +{ + const unsigned char* pinfo = this->pinfo_; + + // Read the offset within the CU. If this is zero, we have reached + // the end of the list. + uint32_t offset; + if (this->offset_size_ == 4) + offset = this->dwinfo_->read_from_pointer<32>(&pinfo); + else + offset = this->dwinfo_->read_from_pointer<64>(&pinfo); + if (offset == 0) + return NULL; + + // Return a pointer to the string at the current location, + // and advance the pointer to the next entry. + const char* ret = reinterpret_cast(pinfo); + while (pinfo < this->buffer_end_ && *pinfo != '\0') + ++pinfo; + if (pinfo < this->buffer_end_) + ++pinfo; + + this->pinfo_ = pinfo; + return ret; +} + +// class Dwarf_die + +Dwarf_die::Dwarf_die( + Dwarf_info_reader* dwinfo, + off_t die_offset, + Dwarf_die* parent) + : dwinfo_(dwinfo), parent_(parent), die_offset_(die_offset), + child_offset_(0), sibling_offset_(0), abbrev_code_(NULL), attributes_(), + attributes_read_(false), name_(NULL), name_off_(-1), linkage_name_(NULL), + linkage_name_off_(-1), string_shndx_(0), specification_(0), + abstract_origin_(0) +{ + size_t len; + const unsigned char* pdie = dwinfo->buffer_at_offset(die_offset); + if (pdie == NULL) + return; + unsigned int code = read_unsigned_LEB_128(pdie, &len); + if (code == 0) + { + if (parent != NULL) + parent->set_sibling_offset(die_offset + len); + return; + } + this->attr_offset_ = len; + + // Lookup the abbrev code in the abbrev table. + this->abbrev_code_ = dwinfo->get_abbrev(code); +} + +// Read all the attributes of the DIE. + +bool +Dwarf_die::read_attributes() +{ + if (this->attributes_read_) + return true; + + gold_assert(this->abbrev_code_ != NULL); + + const unsigned char* pdie = + this->dwinfo_->buffer_at_offset(this->die_offset_); + if (pdie == NULL) + return false; + const unsigned char* pattr = pdie + this->attr_offset_; + + unsigned int nattr = this->abbrev_code_->attributes.size(); + this->attributes_.reserve(nattr); + for (unsigned int i = 0; i < nattr; ++i) + { + size_t len; + unsigned int attr = this->abbrev_code_->attributes[i].attr; + unsigned int form = this->abbrev_code_->attributes[i].form; + if (form == elfcpp::DW_FORM_indirect) + { + form = read_unsigned_LEB_128(pattr, &len); + pattr += len; + } + off_t attr_off = this->die_offset_ + (pattr - pdie); + bool ref_form = false; + Attribute_value attr_value; + attr_value.attr = attr; + attr_value.form = form; + attr_value.aux.shndx = 0; + switch(form) + { + case elfcpp::DW_FORM_flag_present: + attr_value.val.intval = 1; + break; + case elfcpp::DW_FORM_strp: + { + off_t str_off; + if (this->dwinfo_->offset_size() == 4) + str_off = this->dwinfo_->read_from_pointer<32>(&pattr); + else + str_off = this->dwinfo_->read_from_pointer<64>(&pattr); + unsigned int shndx = + this->dwinfo_->lookup_reloc(attr_off, &str_off); + attr_value.aux.shndx = shndx; + attr_value.val.refval = str_off; + break; + } + case elfcpp::DW_FORM_sec_offset: + { + off_t sec_off; + if (this->dwinfo_->offset_size() == 4) + sec_off = this->dwinfo_->read_from_pointer<32>(&pattr); + else + sec_off = this->dwinfo_->read_from_pointer<64>(&pattr); + unsigned int shndx = + this->dwinfo_->lookup_reloc(attr_off, &sec_off); + attr_value.aux.shndx = shndx; + attr_value.val.refval = sec_off; + ref_form = true; + break; + } + case elfcpp::DW_FORM_addr: + case elfcpp::DW_FORM_ref_addr: + { + off_t sec_off; + if (this->dwinfo_->address_size() == 4) + sec_off = this->dwinfo_->read_from_pointer<32>(&pattr); + else + sec_off = this->dwinfo_->read_from_pointer<64>(&pattr); + unsigned int shndx = + this->dwinfo_->lookup_reloc(attr_off, &sec_off); + attr_value.aux.shndx = shndx; + attr_value.val.refval = sec_off; + ref_form = true; + break; + } + case elfcpp::DW_FORM_block1: + attr_value.aux.blocklen = *pattr++; + attr_value.val.blockval = pattr; + pattr += attr_value.aux.blocklen; + break; + case elfcpp::DW_FORM_block2: + attr_value.aux.blocklen = + this->dwinfo_->read_from_pointer<16>(&pattr); + attr_value.val.blockval = pattr; + pattr += attr_value.aux.blocklen; + break; + case elfcpp::DW_FORM_block4: + attr_value.aux.blocklen = + this->dwinfo_->read_from_pointer<32>(&pattr); + attr_value.val.blockval = pattr; + pattr += attr_value.aux.blocklen; + break; + case elfcpp::DW_FORM_block: + case elfcpp::DW_FORM_exprloc: + attr_value.aux.blocklen = read_unsigned_LEB_128(pattr, &len); + attr_value.val.blockval = pattr + len; + pattr += len + attr_value.aux.blocklen; + break; + case elfcpp::DW_FORM_data1: + case elfcpp::DW_FORM_flag: + attr_value.val.intval = *pattr++; + break; + case elfcpp::DW_FORM_ref1: + attr_value.val.refval = *pattr++; + ref_form = true; + break; + case elfcpp::DW_FORM_data2: + attr_value.val.intval = + this->dwinfo_->read_from_pointer<16>(&pattr); + break; + case elfcpp::DW_FORM_ref2: + attr_value.val.refval = + this->dwinfo_->read_from_pointer<16>(&pattr); + ref_form = true; + break; + case elfcpp::DW_FORM_data4: + { + off_t sec_off; + sec_off = this->dwinfo_->read_from_pointer<32>(&pattr); + unsigned int shndx = + this->dwinfo_->lookup_reloc(attr_off, &sec_off); + attr_value.aux.shndx = shndx; + attr_value.val.intval = sec_off; + break; + } + case elfcpp::DW_FORM_ref4: + { + off_t sec_off; + sec_off = this->dwinfo_->read_from_pointer<32>(&pattr); + unsigned int shndx = + this->dwinfo_->lookup_reloc(attr_off, &sec_off); + attr_value.aux.shndx = shndx; + attr_value.val.refval = sec_off; + ref_form = true; + break; + } + case elfcpp::DW_FORM_data8: + { + off_t sec_off; + sec_off = this->dwinfo_->read_from_pointer<64>(&pattr); + unsigned int shndx = + this->dwinfo_->lookup_reloc(attr_off, &sec_off); + attr_value.aux.shndx = shndx; + attr_value.val.intval = sec_off; + break; + } + case elfcpp::DW_FORM_ref_sig8: + attr_value.val.uintval = + this->dwinfo_->read_from_pointer<64>(&pattr); + break; + case elfcpp::DW_FORM_ref8: + { + off_t sec_off; + sec_off = this->dwinfo_->read_from_pointer<64>(&pattr); + unsigned int shndx = + this->dwinfo_->lookup_reloc(attr_off, &sec_off); + attr_value.aux.shndx = shndx; + attr_value.val.refval = sec_off; + ref_form = true; + break; + } + case elfcpp::DW_FORM_ref_udata: + attr_value.val.refval = read_unsigned_LEB_128(pattr, &len); + ref_form = true; + pattr += len; + break; + case elfcpp::DW_FORM_udata: + case elfcpp::DW_FORM_GNU_addr_index: + case elfcpp::DW_FORM_GNU_str_index: + attr_value.val.uintval = read_unsigned_LEB_128(pattr, &len); + pattr += len; + break; + case elfcpp::DW_FORM_sdata: + attr_value.val.intval = read_signed_LEB_128(pattr, &len); + pattr += len; + break; + case elfcpp::DW_FORM_string: + attr_value.val.stringval = reinterpret_cast(pattr); + len = strlen(attr_value.val.stringval); + pattr += len + 1; + break; + default: + return false; + } + + // Cache the most frequently-requested attributes. + switch (attr) + { + case elfcpp::DW_AT_name: + if (form == elfcpp::DW_FORM_string) + this->name_ = attr_value.val.stringval; + else if (form == elfcpp::DW_FORM_strp) + { + // All indirect strings should refer to the same + // string section, so we just save the last one seen. + this->string_shndx_ = attr_value.aux.shndx; + this->name_off_ = attr_value.val.refval; + } + break; + case elfcpp::DW_AT_linkage_name: + case elfcpp::DW_AT_MIPS_linkage_name: + if (form == elfcpp::DW_FORM_string) + this->linkage_name_ = attr_value.val.stringval; + else if (form == elfcpp::DW_FORM_strp) + { + // All indirect strings should refer to the same + // string section, so we just save the last one seen. + this->string_shndx_ = attr_value.aux.shndx; + this->linkage_name_off_ = attr_value.val.refval; + } + break; + case elfcpp::DW_AT_specification: + if (ref_form) + this->specification_ = attr_value.val.refval; + break; + case elfcpp::DW_AT_abstract_origin: + if (ref_form) + this->abstract_origin_ = attr_value.val.refval; + break; + case elfcpp::DW_AT_sibling: + if (ref_form && attr_value.aux.shndx == 0) + this->sibling_offset_ = attr_value.val.refval; + default: + break; + } + + this->attributes_.push_back(attr_value); + } + + // Now that we know where the next DIE begins, record the offset + // to avoid later recalculation. + if (this->has_children()) + this->child_offset_ = this->die_offset_ + (pattr - pdie); + else + this->sibling_offset_ = this->die_offset_ + (pattr - pdie); + + this->attributes_read_ = true; + return true; +} + +// Skip all the attributes of the DIE and return the offset of the next DIE. + +off_t +Dwarf_die::skip_attributes() +{ + gold_assert(this->abbrev_code_ != NULL); + + const unsigned char* pdie = + this->dwinfo_->buffer_at_offset(this->die_offset_); + if (pdie == NULL) + return 0; + const unsigned char* pattr = pdie + this->attr_offset_; + + for (unsigned int i = 0; i < this->abbrev_code_->attributes.size(); ++i) + { + size_t len; + unsigned int form = this->abbrev_code_->attributes[i].form; + if (form == elfcpp::DW_FORM_indirect) + { + form = read_unsigned_LEB_128(pattr, &len); + pattr += len; + } + switch(form) + { + case elfcpp::DW_FORM_flag_present: + break; + case elfcpp::DW_FORM_strp: + case elfcpp::DW_FORM_sec_offset: + pattr += this->dwinfo_->offset_size(); + break; + case elfcpp::DW_FORM_addr: + case elfcpp::DW_FORM_ref_addr: + pattr += this->dwinfo_->address_size(); + break; + case elfcpp::DW_FORM_block1: + pattr += 1 + *pattr; + break; + case elfcpp::DW_FORM_block2: + { + uint16_t block_size; + block_size = this->dwinfo_->read_from_pointer<16>(&pattr); + pattr += block_size; + break; + } + case elfcpp::DW_FORM_block4: + { + uint32_t block_size; + block_size = this->dwinfo_->read_from_pointer<32>(&pattr); + pattr += block_size; + break; + } + case elfcpp::DW_FORM_block: + case elfcpp::DW_FORM_exprloc: + { + uint64_t block_size; + block_size = read_unsigned_LEB_128(pattr, &len); + pattr += len + block_size; + break; + } + case elfcpp::DW_FORM_data1: + case elfcpp::DW_FORM_ref1: + case elfcpp::DW_FORM_flag: + pattr += 1; + break; + case elfcpp::DW_FORM_data2: + case elfcpp::DW_FORM_ref2: + pattr += 2; + break; + case elfcpp::DW_FORM_data4: + case elfcpp::DW_FORM_ref4: + pattr += 4; + break; + case elfcpp::DW_FORM_data8: + case elfcpp::DW_FORM_ref8: + case elfcpp::DW_FORM_ref_sig8: + pattr += 8; + break; + case elfcpp::DW_FORM_ref_udata: + case elfcpp::DW_FORM_udata: + case elfcpp::DW_FORM_GNU_addr_index: + case elfcpp::DW_FORM_GNU_str_index: + read_unsigned_LEB_128(pattr, &len); + pattr += len; + break; + case elfcpp::DW_FORM_sdata: + read_signed_LEB_128(pattr, &len); + pattr += len; + break; + case elfcpp::DW_FORM_string: + len = strlen(reinterpret_cast(pattr)); + pattr += len + 1; + break; + default: + return 0; + } + } + + return this->die_offset_ + (pattr - pdie); +} + +// Get the name of the DIE and cache it. + +void +Dwarf_die::set_name() +{ + if (this->name_ != NULL || !this->read_attributes()) + return; + if (this->name_off_ != -1) + this->name_ = this->dwinfo_->get_string(this->name_off_, + this->string_shndx_); +} + +// Get the linkage name of the DIE and cache it. + +void +Dwarf_die::set_linkage_name() +{ + if (this->linkage_name_ != NULL || !this->read_attributes()) + return; + if (this->linkage_name_off_ != -1) + this->linkage_name_ = this->dwinfo_->get_string(this->linkage_name_off_, + this->string_shndx_); +} + +// Return the value of attribute ATTR. + +const Dwarf_die::Attribute_value* +Dwarf_die::attribute(unsigned int attr) +{ + if (!this->read_attributes()) + return NULL; + for (unsigned int i = 0; i < this->attributes_.size(); ++i) + { + if (this->attributes_[i].attr == attr) + return &this->attributes_[i]; + } + return NULL; +} + +const char* +Dwarf_die::string_attribute(unsigned int attr) +{ + const Attribute_value* attr_val = this->attribute(attr); + if (attr_val == NULL) + return NULL; + switch (attr_val->form) + { + case elfcpp::DW_FORM_string: + return attr_val->val.stringval; + case elfcpp::DW_FORM_strp: + return this->dwinfo_->get_string(attr_val->val.refval, + attr_val->aux.shndx); + default: + return NULL; + } +} + +int64_t +Dwarf_die::int_attribute(unsigned int attr) +{ + const Attribute_value* attr_val = this->attribute(attr); + if (attr_val == NULL) + return 0; + switch (attr_val->form) + { + case elfcpp::DW_FORM_flag_present: + case elfcpp::DW_FORM_data1: + case elfcpp::DW_FORM_flag: + case elfcpp::DW_FORM_data2: + case elfcpp::DW_FORM_data4: + case elfcpp::DW_FORM_data8: + case elfcpp::DW_FORM_sdata: + return attr_val->val.intval; + default: + return 0; + } +} + +uint64_t +Dwarf_die::uint_attribute(unsigned int attr) +{ + const Attribute_value* attr_val = this->attribute(attr); + if (attr_val == NULL) + return 0; + switch (attr_val->form) + { + case elfcpp::DW_FORM_flag_present: + case elfcpp::DW_FORM_data1: + case elfcpp::DW_FORM_flag: + case elfcpp::DW_FORM_data4: + case elfcpp::DW_FORM_data8: + case elfcpp::DW_FORM_ref_sig8: + case elfcpp::DW_FORM_udata: + return attr_val->val.uintval; + default: + return 0; + } +} + +off_t +Dwarf_die::ref_attribute(unsigned int attr, unsigned int* shndx) +{ + const Attribute_value* attr_val = this->attribute(attr); + if (attr_val == NULL) + return -1; + switch (attr_val->form) + { + case elfcpp::DW_FORM_sec_offset: + case elfcpp::DW_FORM_addr: + case elfcpp::DW_FORM_ref_addr: + case elfcpp::DW_FORM_ref1: + case elfcpp::DW_FORM_ref2: + case elfcpp::DW_FORM_ref4: + case elfcpp::DW_FORM_ref8: + case elfcpp::DW_FORM_ref_udata: + *shndx = attr_val->aux.shndx; + return attr_val->val.refval; + case elfcpp::DW_FORM_ref_sig8: + *shndx = attr_val->aux.shndx; + return attr_val->val.uintval; + case elfcpp::DW_FORM_data4: + case elfcpp::DW_FORM_data8: + *shndx = attr_val->aux.shndx; + return attr_val->val.intval; + default: + return -1; + } +} + +off_t +Dwarf_die::address_attribute(unsigned int attr, unsigned int* shndx) +{ + const Attribute_value* attr_val = this->attribute(attr); + if (attr_val == NULL || attr_val->form != elfcpp::DW_FORM_addr) + return -1; + + *shndx = attr_val->aux.shndx; + return attr_val->val.refval; +} + +// Return the offset of this DIE's first child. + +off_t +Dwarf_die::child_offset() +{ + gold_assert(this->abbrev_code_ != NULL); + if (!this->has_children()) + return 0; + if (this->child_offset_ == 0) + this->child_offset_ = this->skip_attributes(); + return this->child_offset_; +} + +// Return the offset of this DIE's next sibling. + +off_t +Dwarf_die::sibling_offset() +{ + gold_assert(this->abbrev_code_ != NULL); + + if (this->sibling_offset_ != 0) + return this->sibling_offset_; + + if (!this->has_children()) + { + this->sibling_offset_ = this->skip_attributes(); + return this->sibling_offset_; + } + + if (this->has_sibling_attribute()) + { + if (!this->read_attributes()) + return 0; + if (this->sibling_offset_ != 0) + return this->sibling_offset_; + } + + // Skip over the children. + off_t child_offset = this->child_offset(); + while (child_offset > 0) + { + Dwarf_die die(this->dwinfo_, child_offset, this); + // The Dwarf_die ctor will set this DIE's sibling offset + // when it reads a zero abbrev code. + if (die.tag() == 0) + break; + child_offset = die.sibling_offset(); + } + + // This should be set by now. If not, there was a problem reading + // the DWARF info, and we return 0. + return this->sibling_offset_; +} + +// class Dwarf_info_reader + +// Begin parsing the debug info. This calls visit_compilation_unit() +// or visit_type_unit() for each compilation or type unit found in the +// section, and visit_die() for each top-level DIE. + +void +Dwarf_info_reader::parse() +{ + if (this->object_->is_big_endian()) + { +#if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG) + this->do_parse(); +#else + gold_unreachable(); +#endif + } + else + { +#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE) + this->do_parse(); +#else + gold_unreachable(); +#endif + } +} + +template +void +Dwarf_info_reader::do_parse() +{ + // Get the section contents and decompress if necessary. + section_size_type buffer_size; + bool buffer_is_new; + this->buffer_ = this->object_->decompressed_section_contents(this->shndx_, + &buffer_size, + &buffer_is_new); + if (this->buffer_ == NULL || buffer_size == 0) + return; + this->buffer_end_ = this->buffer_ + buffer_size; + + // The offset of this input section in the output section. + off_t section_offset = this->object_->output_section_offset(this->shndx_); + + // Start tracking relocations for this section. + this->reloc_mapper_ = make_elf_reloc_mapper(this->object_, this->symtab_, + this->symtab_size_); + this->reloc_mapper_->initialize(this->reloc_shndx_, this->reloc_type_); + + // Loop over compilation units (or type units). + unsigned int abbrev_shndx = this->abbrev_shndx_; + off_t abbrev_offset = 0; + const unsigned char* pinfo = this->buffer_; + while (pinfo < this->buffer_end_) + { + // Read the compilation (or type) unit header. + const unsigned char* cu_start = pinfo; + this->cu_offset_ = cu_start - this->buffer_; + this->cu_length_ = this->buffer_end_ - cu_start; + + // Read unit_length (4 or 12 bytes). + if (!this->check_buffer(pinfo + 4)) + break; + uint32_t unit_length = + elfcpp::Swap_unaligned<32, big_endian>::readval(pinfo); + pinfo += 4; + if (unit_length == 0xffffffff) + { + if (!this->check_buffer(pinfo + 8)) + break; + unit_length = elfcpp::Swap_unaligned<64, big_endian>::readval(pinfo); + pinfo += 8; + this->offset_size_ = 8; + } + else + this->offset_size_ = 4; + if (!this->check_buffer(pinfo + unit_length)) + break; + const unsigned char* cu_end = pinfo + unit_length; + this->cu_length_ = cu_end - cu_start; + if (!this->check_buffer(pinfo + 2 + this->offset_size_ + 1)) + break; + + // Read version (2 bytes). + this->cu_version_ = + elfcpp::Swap_unaligned<16, big_endian>::readval(pinfo); + pinfo += 2; + + // Read debug_abbrev_offset (4 or 8 bytes). + if (this->offset_size_ == 4) + abbrev_offset = elfcpp::Swap_unaligned<32, big_endian>::readval(pinfo); + else + abbrev_offset = elfcpp::Swap_unaligned<64, big_endian>::readval(pinfo); + if (this->reloc_shndx_ > 0) + { + off_t reloc_offset = pinfo - this->buffer_; + off_t value; + abbrev_shndx = + this->reloc_mapper_->get_reloc_target(reloc_offset, &value); + if (abbrev_shndx == 0) + return; + if (this->reloc_type_ == elfcpp::SHT_REL) + abbrev_offset += value; + else + abbrev_offset = value; + } + pinfo += this->offset_size_; + + // Read address_size (1 byte). + this->address_size_ = *pinfo++; + + // For type units, read the two extra fields. + uint64_t signature = 0; + off_t type_offset = 0; + if (this->is_type_unit_) + { + if (!this->check_buffer(pinfo + 8 + this->offset_size_)) + break; + + // Read type_signature (8 bytes). + signature = elfcpp::Swap_unaligned<64, big_endian>::readval(pinfo); + pinfo += 8; + + // Read type_offset (4 or 8 bytes). + if (this->offset_size_ == 4) + type_offset = + elfcpp::Swap_unaligned<32, big_endian>::readval(pinfo); + else + type_offset = + elfcpp::Swap_unaligned<64, big_endian>::readval(pinfo); + pinfo += this->offset_size_; + } + + // Read the .debug_abbrev table. + this->abbrev_table_.read_abbrevs(this->object_, abbrev_shndx, + abbrev_offset); + + // Visit the root DIE. + Dwarf_die root_die(this, + pinfo - (this->buffer_ + this->cu_offset_), + NULL); + if (root_die.tag() != 0) + { + // Visit the CU or TU. + if (this->is_type_unit_) + this->visit_type_unit(section_offset + this->cu_offset_, + type_offset, signature, &root_die); + else + this->visit_compilation_unit(section_offset + this->cu_offset_, + cu_end - cu_start, &root_die); + } + + // Advance to the next CU. + pinfo = cu_end; + } + + if (buffer_is_new) + { + delete[] this->buffer_; + this->buffer_ = NULL; + } +} + +// Read the DWARF string table. + +bool +Dwarf_info_reader::do_read_string_table(unsigned int string_shndx) +{ + Relobj* object = this->object_; + + // If we don't have relocations, string_shndx will be 0, and + // we'll have to hunt for the .debug_str section. + if (string_shndx == 0) + { + for (unsigned int i = 1; i < this->object_->shnum(); ++i) + { + std::string name = object->section_name(i); + if (name == ".debug_str") + { + string_shndx = i; + this->string_output_section_offset_ = + object->output_section_offset(i); + break; + } + } + if (string_shndx == 0) + return false; + } + + if (this->owns_string_buffer_ && this->string_buffer_ != NULL) + { + delete[] this->string_buffer_; + this->owns_string_buffer_ = false; + } + + // Get the secton contents and decompress if necessary. + section_size_type buffer_size; + const unsigned char* buffer = + object->decompressed_section_contents(string_shndx, + &buffer_size, + &this->owns_string_buffer_); + this->string_buffer_ = reinterpret_cast(buffer); + this->string_buffer_end_ = this->string_buffer_ + buffer_size; + this->string_shndx_ = string_shndx; + return true; +} + +// Read a possibly unaligned integer of SIZE. +template +inline typename elfcpp::Valtype_base::Valtype +Dwarf_info_reader::read_from_pointer(const unsigned char* source) +{ + typename elfcpp::Valtype_base::Valtype return_value; + if (this->object_->is_big_endian()) + return_value = elfcpp::Swap_unaligned::readval(source); + else + return_value = elfcpp::Swap_unaligned::readval(source); + return return_value; +} + +// Read a possibly unaligned integer of SIZE. Update SOURCE after read. +template +inline typename elfcpp::Valtype_base::Valtype +Dwarf_info_reader::read_from_pointer(const unsigned char** source) +{ + typename elfcpp::Valtype_base::Valtype return_value; + if (this->object_->is_big_endian()) + return_value = elfcpp::Swap_unaligned::readval(*source); + else + return_value = elfcpp::Swap_unaligned::readval(*source); + *source += valsize / 8; + return return_value; +} + +// Look for a relocation at offset ATTR_OFF in the dwarf info, +// and return the section index and offset of the target. + +unsigned int +Dwarf_info_reader::lookup_reloc(off_t attr_off, off_t* target_off) +{ + off_t value; + attr_off += this->cu_offset_; + unsigned int shndx = this->reloc_mapper_->get_reloc_target(attr_off, &value); + if (shndx == 0) + return 0; + if (this->reloc_type_ == elfcpp::SHT_REL) + *target_off += value; + else + *target_off = value; + return shndx; +} + +// Return a string from the DWARF string table. + +const char* +Dwarf_info_reader::get_string(off_t str_off, unsigned int string_shndx) +{ + if (!this->read_string_table(string_shndx)) + return NULL; + + // Correct the offset. For incremental update links, we have a + // relocated offset that is relative to the output section, but + // here we need an offset relative to the input section. + str_off -= this->string_output_section_offset_; + + const char* p = this->string_buffer_ + str_off; + + if (p < this->string_buffer_ || p >= this->string_buffer_end_) + return NULL; + + return p; +} + +// The following are default, do-nothing, implementations of the +// hook methods normally provided by a derived class. We provide +// default implementations rather than no implementation so that +// a derived class needs to implement only the hooks that it needs +// to use. + +// Process a compilation unit and parse its child DIE. + +void +Dwarf_info_reader::visit_compilation_unit(off_t, off_t, Dwarf_die*) +{ +} + +// Process a type unit and parse its child DIE. + +void +Dwarf_info_reader::visit_type_unit(off_t, off_t, uint64_t, Dwarf_die*) +{ +} + +// Print a warning about a corrupt debug section. + +void +Dwarf_info_reader::warn_corrupt_debug_section() const +{ + gold_warning(_("%s: corrupt debug info in %s"), + this->object_->name().c_str(), + this->object_->section_name(this->shndx_).c_str()); +} + +// class Sized_dwarf_line_info + +struct LineStateMachine +{ + int file_num; + uint64_t address; + int line_num; + int column_num; + unsigned int shndx; // the section address refers to + bool is_stmt; // stmt means statement. + bool basic_block; + bool end_sequence; +}; + +static void +ResetLineStateMachine(struct LineStateMachine* lsm, bool default_is_stmt) +{ + lsm->file_num = 1; + lsm->address = 0; + lsm->line_num = 1; + lsm->column_num = 0; + lsm->shndx = -1U; + lsm->is_stmt = default_is_stmt; + lsm->basic_block = false; + lsm->end_sequence = false; +} + +template +Sized_dwarf_line_info::Sized_dwarf_line_info( + Object* object, + unsigned int read_shndx) + : data_valid_(false), buffer_(NULL), buffer_start_(NULL), + reloc_mapper_(NULL), symtab_buffer_(NULL), directories_(), files_(), + current_header_index_(-1) +{ + unsigned int debug_shndx; + + for (debug_shndx = 1; debug_shndx < object->shnum(); ++debug_shndx) + { + // FIXME: do this more efficiently: section_name() isn't super-fast + std::string name = object->section_name(debug_shndx); + if (name == ".debug_line" || name == ".zdebug_line") + { + section_size_type buffer_size; + bool is_new = false; + this->buffer_ = object->decompressed_section_contents(debug_shndx, + &buffer_size, + &is_new); + if (is_new) + this->buffer_start_ = this->buffer_; + this->buffer_end_ = this->buffer_ + buffer_size; + break; + } + } + if (this->buffer_ == NULL) + return; + + // Find the relocation section for ".debug_line". + // We expect these for relobjs (.o's) but not dynobjs (.so's). + unsigned int reloc_shndx = 0; + for (unsigned int i = 0; i < object->shnum(); ++i) + { + unsigned int reloc_sh_type = object->section_type(i); + if ((reloc_sh_type == elfcpp::SHT_REL + || reloc_sh_type == elfcpp::SHT_RELA) + && object->section_info(i) == debug_shndx) + { + reloc_shndx = i; + this->track_relocs_type_ = reloc_sh_type; + break; + } + } + + // Finally, we need the symtab section to interpret the relocs. + if (reloc_shndx != 0) + { + unsigned int symtab_shndx; + for (symtab_shndx = 0; symtab_shndx < object->shnum(); ++symtab_shndx) + if (object->section_type(symtab_shndx) == elfcpp::SHT_SYMTAB) + { + this->symtab_buffer_ = object->section_contents( + symtab_shndx, &this->symtab_buffer_size_, false); + break; + } + if (this->symtab_buffer_ == NULL) + return; + } + + this->reloc_mapper_ = + new Sized_elf_reloc_mapper(object, + this->symtab_buffer_, + this->symtab_buffer_size_); + if (!this->reloc_mapper_->initialize(reloc_shndx, this->track_relocs_type_)) + return; + + // Now that we have successfully read all the data, parse the debug + // info. + this->data_valid_ = true; + this->read_line_mappings(read_shndx); +} + +// Read the DWARF header. + +template +const unsigned char* +Sized_dwarf_line_info::read_header_prolog( + const unsigned char* lineptr) +{ + uint32_t initial_length = elfcpp::Swap_unaligned<32, big_endian>::readval(lineptr); + lineptr += 4; + + // In DWARF2/3, if the initial length is all 1 bits, then the offset + // size is 8 and we need to read the next 8 bytes for the real length. + if (initial_length == 0xffffffff) + { + header_.offset_size = 8; + initial_length = elfcpp::Swap_unaligned<64, big_endian>::readval(lineptr); + lineptr += 8; + } + else + header_.offset_size = 4; + + header_.total_length = initial_length; + + gold_assert(lineptr + header_.total_length <= buffer_end_); + + header_.version = elfcpp::Swap_unaligned<16, big_endian>::readval(lineptr); + lineptr += 2; + + if (header_.offset_size == 4) + header_.prologue_length = elfcpp::Swap_unaligned<32, big_endian>::readval(lineptr); + else + header_.prologue_length = elfcpp::Swap_unaligned<64, big_endian>::readval(lineptr); + lineptr += header_.offset_size; + + header_.min_insn_length = *lineptr; + lineptr += 1; + + header_.default_is_stmt = *lineptr; + lineptr += 1; + + header_.line_base = *reinterpret_cast(lineptr); + lineptr += 1; + + header_.line_range = *lineptr; + lineptr += 1; + + header_.opcode_base = *lineptr; + lineptr += 1; + + header_.std_opcode_lengths.resize(header_.opcode_base + 1); + header_.std_opcode_lengths[0] = 0; + for (int i = 1; i < header_.opcode_base; i++) + { + header_.std_opcode_lengths[i] = *lineptr; + lineptr += 1; + } + + return lineptr; +} + +// The header for a debug_line section is mildly complicated, because +// the line info is very tightly encoded. + +template +const unsigned char* +Sized_dwarf_line_info::read_header_tables( + const unsigned char* lineptr) +{ + ++this->current_header_index_; + + // Create a new directories_ entry and a new files_ entry for our new + // header. We initialize each with a single empty element, because + // dwarf indexes directory and filenames starting at 1. + gold_assert(static_cast(this->directories_.size()) + == this->current_header_index_); + gold_assert(static_cast(this->files_.size()) + == this->current_header_index_); + this->directories_.push_back(std::vector(1)); + this->files_.push_back(std::vector >(1)); + + // It is legal for the directory entry table to be empty. + if (*lineptr) + { + int dirindex = 1; + while (*lineptr) + { + const char* dirname = reinterpret_cast(lineptr); + gold_assert(dirindex + == static_cast(this->directories_.back().size())); + this->directories_.back().push_back(dirname); + lineptr += this->directories_.back().back().size() + 1; + dirindex++; + } + } + lineptr++; + + // It is also legal for the file entry table to be empty. + if (*lineptr) + { + int fileindex = 1; + size_t len; + while (*lineptr) + { + const char* filename = reinterpret_cast(lineptr); + lineptr += strlen(filename) + 1; + + uint64_t dirindex = read_unsigned_LEB_128(lineptr, &len); + lineptr += len; + + if (dirindex >= this->directories_.back().size()) + dirindex = 0; + int dirindexi = static_cast(dirindex); + + read_unsigned_LEB_128(lineptr, &len); // mod_time + lineptr += len; + + read_unsigned_LEB_128(lineptr, &len); // filelength + lineptr += len; + + gold_assert(fileindex + == static_cast(this->files_.back().size())); + this->files_.back().push_back(std::make_pair(dirindexi, filename)); + fileindex++; + } + } + lineptr++; + + return lineptr; +} + +// Process a single opcode in the .debug.line structure. + +template +bool +Sized_dwarf_line_info::process_one_opcode( + const unsigned char* start, struct LineStateMachine* lsm, size_t* len) +{ + size_t oplen = 0; + size_t templen; + unsigned char opcode = *start; + oplen++; + start++; + + // If the opcode is great than the opcode_base, it is a special + // opcode. Most line programs consist mainly of special opcodes. + if (opcode >= header_.opcode_base) + { + opcode -= header_.opcode_base; + const int advance_address = ((opcode / header_.line_range) + * header_.min_insn_length); + lsm->address += advance_address; + + const int advance_line = ((opcode % header_.line_range) + + header_.line_base); + lsm->line_num += advance_line; + lsm->basic_block = true; + *len = oplen; + return true; + } + + // Otherwise, we have the regular opcodes + switch (opcode) + { + case elfcpp::DW_LNS_copy: + lsm->basic_block = false; + *len = oplen; + return true; + + case elfcpp::DW_LNS_advance_pc: + { + const uint64_t advance_address + = read_unsigned_LEB_128(start, &templen); + oplen += templen; + lsm->address += header_.min_insn_length * advance_address; + } + break; + + case elfcpp::DW_LNS_advance_line: + { + const uint64_t advance_line = read_signed_LEB_128(start, &templen); + oplen += templen; + lsm->line_num += advance_line; + } + break; + + case elfcpp::DW_LNS_set_file: + { + const uint64_t fileno = read_unsigned_LEB_128(start, &templen); + oplen += templen; + lsm->file_num = fileno; + } + break; + + case elfcpp::DW_LNS_set_column: + { + const uint64_t colno = read_unsigned_LEB_128(start, &templen); + oplen += templen; + lsm->column_num = colno; + } + break; + + case elfcpp::DW_LNS_negate_stmt: + lsm->is_stmt = !lsm->is_stmt; + break; + + case elfcpp::DW_LNS_set_basic_block: + lsm->basic_block = true; + break; + + case elfcpp::DW_LNS_fixed_advance_pc: + { + int advance_address; + advance_address = elfcpp::Swap_unaligned<16, big_endian>::readval(start); + oplen += 2; + lsm->address += advance_address; + } + break; + + case elfcpp::DW_LNS_const_add_pc: + { + const int advance_address = (header_.min_insn_length + * ((255 - header_.opcode_base) + / header_.line_range)); + lsm->address += advance_address; + } + break; + + case elfcpp::DW_LNS_extended_op: + { + const uint64_t extended_op_len + = read_unsigned_LEB_128(start, &templen); + start += templen; + oplen += templen + extended_op_len; + + const unsigned char extended_op = *start; + start++; + + switch (extended_op) + { + case elfcpp::DW_LNE_end_sequence: + // This means that the current byte is the one immediately + // after a set of instructions. Record the current line + // for up to one less than the current address. + lsm->line_num = -1; + lsm->end_sequence = true; + *len = oplen; + return true; + + case elfcpp::DW_LNE_set_address: + { + lsm->address = + elfcpp::Swap_unaligned::readval(start); + typename Reloc_map::const_iterator it + = this->reloc_map_.find(start - this->buffer_); + if (it != reloc_map_.end()) + { + // If this is a SHT_RELA section, then ignore the + // section contents. This assumes that this is a + // straight reloc which just uses the reloc addend. + // The reloc addend has already been included in the + // symbol value. + if (this->track_relocs_type_ == elfcpp::SHT_RELA) + lsm->address = 0; + // Add in the symbol value. + lsm->address += it->second.second; + lsm->shndx = it->second.first; + } + else + { + // If we're a normal .o file, with relocs, every + // set_address should have an associated relocation. + if (this->input_is_relobj()) + this->data_valid_ = false; + } + break; + } + case elfcpp::DW_LNE_define_file: + { + const char* filename = reinterpret_cast(start); + templen = strlen(filename) + 1; + start += templen; + + uint64_t dirindex = read_unsigned_LEB_128(start, &templen); + + if (dirindex >= this->directories_.back().size()) + dirindex = 0; + int dirindexi = static_cast(dirindex); + + // This opcode takes two additional ULEB128 parameters + // (mod_time and filelength), but we don't use those + // values. Because OPLEN already tells us how far to + // skip to the next opcode, we don't need to read + // them at all. + + this->files_.back().push_back(std::make_pair(dirindexi, + filename)); + } + break; + } + } + break; + + default: + { + // Ignore unknown opcode silently + for (int i = 0; i < header_.std_opcode_lengths[opcode]; i++) + { + size_t templen; + read_unsigned_LEB_128(start, &templen); + start += templen; + oplen += templen; + } + } + break; + } + *len = oplen; + return false; +} + +// Read the debug information at LINEPTR and store it in the line +// number map. + +template +unsigned const char* +Sized_dwarf_line_info::read_lines(unsigned const char* lineptr, + unsigned int shndx) +{ + struct LineStateMachine lsm; + + // LENGTHSTART is the place the length field is based on. It is the + // point in the header after the initial length field. + const unsigned char* lengthstart = buffer_; + + // In 64 bit dwarf, the initial length is 12 bytes, because of the + // 0xffffffff at the start. + if (header_.offset_size == 8) + lengthstart += 12; + else + lengthstart += 4; + + while (lineptr < lengthstart + header_.total_length) + { + ResetLineStateMachine(&lsm, header_.default_is_stmt); + while (!lsm.end_sequence) + { + size_t oplength; + bool add_line = this->process_one_opcode(lineptr, &lsm, &oplength); + if (add_line + && (shndx == -1U || lsm.shndx == -1U || shndx == lsm.shndx)) + { + Offset_to_lineno_entry entry + = { static_cast(lsm.address), + this->current_header_index_, + static_cast(lsm.file_num), + true, lsm.line_num }; + std::vector& + map(this->line_number_map_[lsm.shndx]); + // If we see two consecutive entries with the same + // offset and a real line number, then mark the first + // one as non-canonical. + if (!map.empty() + && (map.back().offset == static_cast(lsm.address)) + && lsm.line_num != -1 + && map.back().line_num != -1) + map.back().last_line_for_offset = false; + map.push_back(entry); + } + lineptr += oplength; + } + } + + return lengthstart + header_.total_length; +} + +// Read the relocations into a Reloc_map. + +template +void +Sized_dwarf_line_info::read_relocs() +{ + if (this->symtab_buffer_ == NULL) + return; + + off_t value; + off_t reloc_offset; + while ((reloc_offset = this->reloc_mapper_->next_offset()) != -1) + { + const unsigned int shndx = + this->reloc_mapper_->get_reloc_target(reloc_offset, &value); + + // There is no reason to record non-ordinary section indexes, or + // SHN_UNDEF, because they will never match the real section. + if (shndx != 0) + this->reloc_map_[reloc_offset] = std::make_pair(shndx, value); + + this->reloc_mapper_->advance(reloc_offset + 1); + } +} + +// Read the line number info. + +template +void +Sized_dwarf_line_info::read_line_mappings(unsigned int shndx) +{ + gold_assert(this->data_valid_ == true); + + this->read_relocs(); + while (this->buffer_ < this->buffer_end_) + { + const unsigned char* lineptr = this->buffer_; + lineptr = this->read_header_prolog(lineptr); + lineptr = this->read_header_tables(lineptr); + lineptr = this->read_lines(lineptr, shndx); + this->buffer_ = lineptr; + } + + // Sort the lines numbers, so addr2line can use binary search. + for (typename Lineno_map::iterator it = line_number_map_.begin(); + it != line_number_map_.end(); + ++it) + // Each vector needs to be sorted by offset. + std::sort(it->second.begin(), it->second.end()); +} + +// Some processing depends on whether the input is a .o file or not. +// For instance, .o files have relocs, and have .debug_lines +// information on a per section basis. .so files, on the other hand, +// lack relocs, and offsets are unique, so we can ignore the section +// information. + +template +bool +Sized_dwarf_line_info::input_is_relobj() +{ + // Only .o files have relocs and the symtab buffer that goes with them. + return this->symtab_buffer_ != NULL; +} + +// Given an Offset_to_lineno_entry vector, and an offset, figure out +// if the offset points into a function according to the vector (see +// comments below for the algorithm). If it does, return an iterator +// into the vector that points to the line-number that contains that +// offset. If not, it returns vector::end(). + +static std::vector::const_iterator +offset_to_iterator(const std::vector* offsets, + off_t offset) +{ + const Offset_to_lineno_entry lookup_key = { offset, 0, 0, true, 0 }; + + // lower_bound() returns the smallest offset which is >= lookup_key. + // If no offset in offsets is >= lookup_key, returns end(). + std::vector::const_iterator it + = std::lower_bound(offsets->begin(), offsets->end(), lookup_key); + + // This code is easiest to understand with a concrete example. + // Here's a possible offsets array: + // {{offset = 3211, header_num = 0, file_num = 1, last, line_num = 16}, // 0 + // {offset = 3224, header_num = 0, file_num = 1, last, line_num = 20}, // 1 + // {offset = 3226, header_num = 0, file_num = 1, last, line_num = 22}, // 2 + // {offset = 3231, header_num = 0, file_num = 1, last, line_num = 25}, // 3 + // {offset = 3232, header_num = 0, file_num = 1, last, line_num = -1}, // 4 + // {offset = 3232, header_num = 0, file_num = 1, last, line_num = 65}, // 5 + // {offset = 3235, header_num = 0, file_num = 1, last, line_num = 66}, // 6 + // {offset = 3236, header_num = 0, file_num = 1, last, line_num = -1}, // 7 + // {offset = 5764, header_num = 0, file_num = 1, last, line_num = 48}, // 8 + // {offset = 5764, header_num = 0, file_num = 1,!last, line_num = 47}, // 9 + // {offset = 5765, header_num = 0, file_num = 1, last, line_num = 49}, // 10 + // {offset = 5767, header_num = 0, file_num = 1, last, line_num = 50}, // 11 + // {offset = 5768, header_num = 0, file_num = 1, last, line_num = 51}, // 12 + // {offset = 5773, header_num = 0, file_num = 1, last, line_num = -1}, // 13 + // {offset = 5787, header_num = 1, file_num = 1, last, line_num = 19}, // 14 + // {offset = 5790, header_num = 1, file_num = 1, last, line_num = 20}, // 15 + // {offset = 5793, header_num = 1, file_num = 1, last, line_num = 67}, // 16 + // {offset = 5793, header_num = 1, file_num = 1, last, line_num = -1}, // 17 + // {offset = 5793, header_num = 1, file_num = 1,!last, line_num = 66}, // 18 + // {offset = 5795, header_num = 1, file_num = 1, last, line_num = 68}, // 19 + // {offset = 5798, header_num = 1, file_num = 1, last, line_num = -1}, // 20 + // The entries with line_num == -1 mark the end of a function: the + // associated offset is one past the last instruction in the + // function. This can correspond to the beginning of the next + // function (as is true for offset 3232); alternately, there can be + // a gap between the end of one function and the start of the next + // (as is true for some others, most obviously from 3236->5764). + // + // Case 1: lookup_key has offset == 10. lower_bound returns + // offsets[0]. Since it's not an exact match and we're + // at the beginning of offsets, we return end() (invalid). + // Case 2: lookup_key has offset 10000. lower_bound returns + // offset[21] (end()). We return end() (invalid). + // Case 3: lookup_key has offset == 3211. lower_bound matches + // offsets[0] exactly, and that's the entry we return. + // Case 4: lookup_key has offset == 3232. lower_bound returns + // offsets[4]. That's an exact match, but indicates + // end-of-function. We check if offsets[5] is also an + // exact match but not end-of-function. It is, so we + // return offsets[5]. + // Case 5: lookup_key has offset == 3214. lower_bound returns + // offsets[1]. Since it's not an exact match, we back + // up to the offset that's < lookup_key, offsets[0]. + // We note offsets[0] is a valid entry (not end-of-function), + // so that's the entry we return. + // Case 6: lookup_key has offset == 4000. lower_bound returns + // offsets[8]. Since it's not an exact match, we back + // up to offsets[7]. Since offsets[7] indicates + // end-of-function, we know lookup_key is between + // functions, so we return end() (not a valid offset). + // Case 7: lookup_key has offset == 5794. lower_bound returns + // offsets[19]. Since it's not an exact match, we back + // up to offsets[16]. Note we back up to the *first* + // entry with offset 5793, not just offsets[19-1]. + // We note offsets[16] is a valid entry, so we return it. + // If offsets[16] had had line_num == -1, we would have + // checked offsets[17]. The reason for this is that + // 16 and 17 can be in an arbitrary order, since we sort + // only by offset and last_line_for_offset. (Note it + // doesn't help to use line_number as a tertiary sort key, + // since sometimes we want the -1 to be first and sometimes + // we want it to be last.) + + // This deals with cases (1) and (2). + if ((it == offsets->begin() && offset < it->offset) + || it == offsets->end()) + return offsets->end(); + + // This deals with cases (3) and (4). + if (offset == it->offset) + { + while (it != offsets->end() + && it->offset == offset + && it->line_num == -1) + ++it; + if (it == offsets->end() || it->offset != offset) + return offsets->end(); + else + return it; + } + + // This handles the first part of case (7) -- we back up to the + // *first* entry that has the offset that's behind us. + gold_assert(it != offsets->begin()); + std::vector::const_iterator range_end = it; + --it; + const off_t range_value = it->offset; + while (it != offsets->begin() && (it-1)->offset == range_value) + --it; + + // This handles cases (5), (6), and (7): if any entry in the + // equal_range [it, range_end) has a line_num != -1, it's a valid + // match. If not, we're not in a function. The line number we saw + // last for an offset will be sorted first, so it'll get returned if + // it's present. + for (; it != range_end; ++it) + if (it->line_num != -1) + return it; + return offsets->end(); +} + +// Returns the canonical filename:lineno for the address passed in. +// If other_lines is not NULL, appends the non-canonical lines +// assigned to the same address. + +template +std::string +Sized_dwarf_line_info::do_addr2line( + unsigned int shndx, + off_t offset, + std::vector* other_lines) +{ + if (this->data_valid_ == false) + return ""; + + const std::vector* offsets; + // If we do not have reloc information, then our input is a .so or + // some similar data structure where all the information is held in + // the offset. In that case, we ignore the input shndx. + if (this->input_is_relobj()) + offsets = &this->line_number_map_[shndx]; + else + offsets = &this->line_number_map_[-1U]; + if (offsets->empty()) + return ""; + + typename std::vector::const_iterator it + = offset_to_iterator(offsets, offset); + if (it == offsets->end()) + return ""; + + std::string result = this->format_file_lineno(*it); + if (other_lines != NULL) + for (++it; it != offsets->end() && it->offset == offset; ++it) + { + if (it->line_num == -1) + continue; // The end of a previous function. + other_lines->push_back(this->format_file_lineno(*it)); + } + return result; +} + +// Convert the file_num + line_num into a string. + +template +std::string +Sized_dwarf_line_info::format_file_lineno( + const Offset_to_lineno_entry& loc) const +{ + std::string ret; + + gold_assert(loc.header_num < static_cast(this->files_.size())); + gold_assert(loc.file_num + < static_cast(this->files_[loc.header_num].size())); + const std::pair& filename_pair + = this->files_[loc.header_num][loc.file_num]; + const std::string& filename = filename_pair.second; + + gold_assert(loc.header_num < static_cast(this->directories_.size())); + gold_assert(filename_pair.first + < static_cast(this->directories_[loc.header_num].size())); + const std::string& dirname + = this->directories_[loc.header_num][filename_pair.first]; + + if (!dirname.empty()) + { + ret += dirname; + ret += "/"; + } + ret += filename; + if (ret.empty()) + ret = "(unknown)"; + + char buffer[64]; // enough to hold a line number + snprintf(buffer, sizeof(buffer), "%d", loc.line_num); + ret += ":"; + ret += buffer; + + return ret; +} + +// Dwarf_line_info routines. + +static unsigned int next_generation_count = 0; + +struct Addr2line_cache_entry +{ + Object* object; + unsigned int shndx; + Dwarf_line_info* dwarf_line_info; + unsigned int generation_count; + unsigned int access_count; + + Addr2line_cache_entry(Object* o, unsigned int s, Dwarf_line_info* d) + : object(o), shndx(s), dwarf_line_info(d), + generation_count(next_generation_count), access_count(0) + { + if (next_generation_count < (1U << 31)) + ++next_generation_count; + } +}; +// We expect this cache to be small, so don't bother with a hashtable +// or priority queue or anything: just use a simple vector. +static std::vector addr2line_cache; + +std::string +Dwarf_line_info::one_addr2line(Object* object, + unsigned int shndx, off_t offset, + size_t cache_size, + std::vector* other_lines) +{ + Dwarf_line_info* lineinfo = NULL; + std::vector::iterator it; + + // First, check the cache. If we hit, update the counts. + for (it = addr2line_cache.begin(); it != addr2line_cache.end(); ++it) + { + if (it->object == object && it->shndx == shndx) + { + lineinfo = it->dwarf_line_info; + it->generation_count = next_generation_count; + // We cap generation_count at 2^31 -1 to avoid overflow. + if (next_generation_count < (1U << 31)) + ++next_generation_count; + // We cap access_count at 31 so 2^access_count doesn't overflow + if (it->access_count < 31) + ++it->access_count; + break; + } + } + + // If we don't hit the cache, create a new object and insert into the + // cache. + if (lineinfo == NULL) + { + switch (parameters->size_and_endianness()) + { +#ifdef HAVE_TARGET_32_LITTLE + case Parameters::TARGET_32_LITTLE: + lineinfo = new Sized_dwarf_line_info<32, false>(object, shndx); break; +#endif +#ifdef HAVE_TARGET_32_BIG + case Parameters::TARGET_32_BIG: + lineinfo = new Sized_dwarf_line_info<32, true>(object, shndx); break; +#endif +#ifdef HAVE_TARGET_64_LITTLE + case Parameters::TARGET_64_LITTLE: + lineinfo = new Sized_dwarf_line_info<64, false>(object, shndx); break; +#endif +#ifdef HAVE_TARGET_64_BIG + case Parameters::TARGET_64_BIG: + lineinfo = new Sized_dwarf_line_info<64, true>(object, shndx); break; +#endif + default: + gold_unreachable(); + } + addr2line_cache.push_back(Addr2line_cache_entry(object, shndx, lineinfo)); + } + + // Now that we have our object, figure out the answer + std::string retval = lineinfo->addr2line(shndx, offset, other_lines); + + // Finally, if our cache has grown too big, delete old objects. We + // assume the common (probably only) case is deleting only one object. + // We use a pretty simple scheme to evict: function of LRU and MFU. + while (addr2line_cache.size() > cache_size) + { + unsigned int lowest_score = ~0U; + std::vector::iterator lowest + = addr2line_cache.end(); + for (it = addr2line_cache.begin(); it != addr2line_cache.end(); ++it) + { + const unsigned int score = (it->generation_count + + (1U << it->access_count)); + if (score < lowest_score) + { + lowest_score = score; + lowest = it; + } + } + if (lowest != addr2line_cache.end()) + { + delete lowest->dwarf_line_info; + addr2line_cache.erase(lowest); + } + } + + return retval; +} + +void +Dwarf_line_info::clear_addr2line_cache() +{ + for (std::vector::iterator it = addr2line_cache.begin(); + it != addr2line_cache.end(); + ++it) + delete it->dwarf_line_info; + addr2line_cache.clear(); +} + +#ifdef HAVE_TARGET_32_LITTLE +template +class Sized_dwarf_line_info<32, false>; +#endif + +#ifdef HAVE_TARGET_32_BIG +template +class Sized_dwarf_line_info<32, true>; +#endif + +#ifdef HAVE_TARGET_64_LITTLE +template +class Sized_dwarf_line_info<64, false>; +#endif + +#ifdef HAVE_TARGET_64_BIG +template +class Sized_dwarf_line_info<64, true>; +#endif + +} // End namespace gold. diff --git a/binutils-2.25/gold/dwarf_reader.h b/binutils-2.25/gold/dwarf_reader.h new file mode 100644 index 00000000..86d80bb1 --- /dev/null +++ b/binutils-2.25/gold/dwarf_reader.h @@ -0,0 +1,1117 @@ +// dwarf_reader.h -- parse dwarf2/3 debug information for gold -*- C++ -*- + +// Copyright 2007, 2008, 2009, 2010, 2011, 2012, 2013 +// Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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. + +#ifndef GOLD_DWARF_READER_H +#define GOLD_DWARF_READER_H + +#include +#include +#include +#include + +#include "elfcpp.h" +#include "elfcpp_swap.h" +#include "dwarf.h" +#include "reloc.h" + +namespace gold +{ + +class Dwarf_info_reader; +struct LineStateMachine; + +// This class is used to extract the section index and offset of +// the target of a relocation for a given offset within the section. + +class Elf_reloc_mapper +{ + public: + Elf_reloc_mapper() + { } + + virtual + ~Elf_reloc_mapper() + { } + + // Initialize the relocation tracker for section RELOC_SHNDX. + bool + initialize(unsigned int reloc_shndx, unsigned int reloc_type) + { return this->do_initialize(reloc_shndx, reloc_type); } + + // Return the next reloc_offset. + off_t + next_offset() + { return this->do_next_offset(); } + + // Advance to the next relocation past OFFSET. + void + advance(off_t offset) + { this->do_advance(offset); } + + // Return the section index and offset within the section of the target + // of the relocation for RELOC_OFFSET in the referring section. + unsigned int + get_reloc_target(off_t reloc_offset, off_t* target_offset) + { return this->do_get_reloc_target(reloc_offset, target_offset); } + + // Checkpoint the current position in the reloc section. + uint64_t + checkpoint() const + { return this->do_checkpoint(); } + + // Reset the current position to the CHECKPOINT. + void + reset(uint64_t checkpoint) + { this->do_reset(checkpoint); } + + protected: + virtual bool + do_initialize(unsigned int, unsigned int) = 0; + + // Return the next reloc_offset. + virtual off_t + do_next_offset() = 0; + + // Advance to the next relocation past OFFSET. + virtual void + do_advance(off_t offset) = 0; + + virtual unsigned int + do_get_reloc_target(off_t reloc_offset, off_t* target_offset) = 0; + + // Checkpoint the current position in the reloc section. + virtual uint64_t + do_checkpoint() const = 0; + + // Reset the current position to the CHECKPOINT. + virtual void + do_reset(uint64_t checkpoint) = 0; +}; + +template +class Sized_elf_reloc_mapper : public Elf_reloc_mapper +{ + public: + Sized_elf_reloc_mapper(Object* object, const unsigned char* symtab, + off_t symtab_size) + : object_(object), symtab_(symtab), symtab_size_(symtab_size), + reloc_type_(0), track_relocs_() + { } + + protected: + bool + do_initialize(unsigned int reloc_shndx, unsigned int reloc_type); + + // Return the next reloc_offset. + virtual off_t + do_next_offset() + { return this->track_relocs_.next_offset(); } + + // Advance to the next relocation past OFFSET. + virtual void + do_advance(off_t offset) + { this->track_relocs_.advance(offset); } + + unsigned int + do_get_reloc_target(off_t reloc_offset, off_t* target_offset); + + // Checkpoint the current position in the reloc section. + uint64_t + do_checkpoint() const + { return this->track_relocs_.checkpoint(); } + + // Reset the current position to the CHECKPOINT. + void + do_reset(uint64_t checkpoint) + { this->track_relocs_.reset(checkpoint); } + + private: + typedef typename elfcpp::Elf_types::Elf_Addr Address; + + // Return the section index of symbol SYMNDX, and copy its value to *VALUE. + // Set *IS_ORDINARY true if the section index is an ordinary section index. + unsigned int + symbol_section(unsigned int symndx, Address* value, bool* is_ordinary); + + // The object file. + Object* object_; + // The ELF symbol table. + const unsigned char* symtab_; + // The size of the ELF symbol table. + off_t symtab_size_; + // Type of the relocation section (SHT_REL or SHT_RELA). + unsigned int reloc_type_; + // Relocations for the referring section. + Track_relocs track_relocs_; +}; + +// This class is used to read the abbreviations table from the +// .debug_abbrev section of the object file. + +class Dwarf_abbrev_table +{ + public: + // An attribute list entry. + struct Attribute + { + Attribute(unsigned int a, unsigned int f) + : attr(a), form(f) + { } + unsigned int attr; + unsigned int form; + }; + + // An abbrev code entry. + struct Abbrev_code + { + Abbrev_code(unsigned int t, bool hc) + : tag(t), has_children(hc), has_sibling_attribute(false), attributes() + { + this->attributes.reserve(10); + } + + void + add_attribute(unsigned int attr, unsigned int form) + { + this->attributes.push_back(Attribute(attr, form)); + } + + // The DWARF tag. + unsigned int tag; + // True if the DIE has children. + bool has_children : 1; + // True if the DIE has a sibling attribute. + bool has_sibling_attribute : 1; + // The list of attributes and forms. + std::vector attributes; + }; + + Dwarf_abbrev_table() + : abbrev_shndx_(0), abbrev_offset_(0), buffer_(NULL), buffer_end_(NULL), + owns_buffer_(false), buffer_pos_(NULL), high_abbrev_codes_() + { + memset(this->low_abbrev_codes_, 0, sizeof(this->low_abbrev_codes_)); + } + + ~Dwarf_abbrev_table() + { + if (this->owns_buffer_ && this->buffer_ != NULL) + delete[] this->buffer_; + this->clear_abbrev_codes(); + } + + // Read the abbrev table from an object file. + bool + read_abbrevs(Relobj* object, + unsigned int abbrev_shndx, + off_t abbrev_offset) + { + // If we've already read this abbrev table, return immediately. + if (this->abbrev_shndx_ > 0 + && this->abbrev_shndx_ == abbrev_shndx + && this->abbrev_offset_ == abbrev_offset) + return true; + return this->do_read_abbrevs(object, abbrev_shndx, abbrev_offset); + } + + // Return the abbrev code entry for CODE. This is a fast path for + // abbrev codes that are in the direct lookup table. If not found + // there, we call do_get_abbrev() to do the hard work. + const Abbrev_code* + get_abbrev(unsigned int code) + { + if (code < this->low_abbrev_code_max_ + && this->low_abbrev_codes_[code] != NULL) + return this->low_abbrev_codes_[code]; + return this->do_get_abbrev(code); + } + + private: + // Read the abbrev table from an object file. + bool + do_read_abbrevs(Relobj* object, + unsigned int abbrev_shndx, + off_t abbrev_offset); + + // Lookup the abbrev code entry for CODE. + const Abbrev_code* + do_get_abbrev(unsigned int code); + + // Store an abbrev code entry for CODE. + void + store_abbrev(unsigned int code, const Abbrev_code* entry) + { + if (code < this->low_abbrev_code_max_) + this->low_abbrev_codes_[code] = entry; + else + this->high_abbrev_codes_[code] = entry; + } + + // Clear the abbrev code table and release the memory it uses. + void + clear_abbrev_codes(); + + typedef Unordered_map Abbrev_code_table; + + // The section index of the current abbrev table. + unsigned int abbrev_shndx_; + // The offset within the section of the current abbrev table. + off_t abbrev_offset_; + // The buffer containing the .debug_abbrev section. + const unsigned char* buffer_; + const unsigned char* buffer_end_; + // True if this object owns the buffer and needs to delete it. + bool owns_buffer_; + // Pointer to the current position in the buffer. + const unsigned char* buffer_pos_; + // The table of abbrev codes. + // We use a direct-lookup array for low abbrev codes, + // and store the rest in a hash table. + static const unsigned int low_abbrev_code_max_ = 256; + const Abbrev_code* low_abbrev_codes_[low_abbrev_code_max_]; + Abbrev_code_table high_abbrev_codes_; +}; + +// A DWARF range list. The start and end offsets are relative +// to the input section SHNDX. Each range must lie entirely +// within a single section. + +class Dwarf_range_list +{ + public: + struct Range + { + Range(unsigned int a_shndx, off_t a_start, off_t a_end) + : shndx(a_shndx), start(a_start), end(a_end) + { } + + unsigned int shndx; + off_t start; + off_t end; + }; + + Dwarf_range_list() + : range_list_() + { } + + void + add(unsigned int shndx, off_t start, off_t end) + { this->range_list_.push_back(Range(shndx, start, end)); } + + size_t + size() const + { return this->range_list_.size(); } + + const Range& + operator[](off_t i) const + { return this->range_list_[i]; } + + private: + std::vector range_list_; +}; + +// This class is used to read the ranges table from the +// .debug_ranges section of the object file. + +class Dwarf_ranges_table +{ + public: + Dwarf_ranges_table(Dwarf_info_reader* dwinfo) + : dwinfo_(dwinfo), ranges_shndx_(0), ranges_buffer_(NULL), + ranges_buffer_end_(NULL), owns_ranges_buffer_(false), + ranges_reloc_mapper_(NULL), reloc_type_(0), output_section_offset_(0) + { } + + ~Dwarf_ranges_table() + { + if (this->owns_ranges_buffer_ && this->ranges_buffer_ != NULL) + delete[] this->ranges_buffer_; + if (this->ranges_reloc_mapper_ != NULL) + delete this->ranges_reloc_mapper_; + } + + // Read the ranges table from an object file. + bool + read_ranges_table(Relobj* object, + const unsigned char* symtab, + off_t symtab_size, + unsigned int ranges_shndx); + + // Read the range table from an object file. + Dwarf_range_list* + read_range_list(Relobj* object, + const unsigned char* symtab, + off_t symtab_size, + unsigned int address_size, + unsigned int ranges_shndx, + off_t ranges_offset); + + // Look for a relocation at offset OFF in the range table, + // and return the section index and offset of the target. + unsigned int + lookup_reloc(off_t off, off_t* target_off); + + private: + // The Dwarf_info_reader, for reading data. + Dwarf_info_reader* dwinfo_; + // The section index of the ranges table. + unsigned int ranges_shndx_; + // The buffer containing the .debug_ranges section. + const unsigned char* ranges_buffer_; + const unsigned char* ranges_buffer_end_; + // True if this object owns the buffer and needs to delete it. + bool owns_ranges_buffer_; + // Relocation mapper for the .debug_ranges section. + Elf_reloc_mapper* ranges_reloc_mapper_; + // Type of the relocation section (SHT_REL or SHT_RELA). + unsigned int reloc_type_; + // For incremental update links, this will hold the offset of the + // input section within the output section. Offsets read from + // relocated data will be relative to the output section, and need + // to be corrected before reading data from the input section. + uint64_t output_section_offset_; +}; + +// This class is used to read the pubnames and pubtypes tables from the +// .debug_pubnames and .debug_pubtypes sections of the object file. + +class Dwarf_pubnames_table +{ + public: + Dwarf_pubnames_table(Dwarf_info_reader* dwinfo, bool is_pubtypes) + : dwinfo_(dwinfo), buffer_(NULL), buffer_end_(NULL), owns_buffer_(false), + offset_size_(0), pinfo_(NULL), is_pubtypes_(is_pubtypes), + output_section_offset_(0), unit_length_(0), cu_offset_(0) + { } + + ~Dwarf_pubnames_table() + { + if (this->owns_buffer_ && this->buffer_ != NULL) + delete[] this->buffer_; + } + + // Read the pubnames section from the object file, using the symbol + // table for relocating it. + bool + read_section(Relobj* object, const unsigned char* symbol_table, + off_t symtab_size); + + // Read the header for the set at OFFSET. + bool + read_header(off_t offset); + + // Return the offset to the cu within the info or types section. + off_t + cu_offset() + { return this->cu_offset_; } + + // Return the size of this subsection of the table. The unit length + // doesn't include the size of its own field. + off_t + subsection_size() + { return this->unit_length_; } + + // Read the next name from the set. + const char* + next_name(); + + private: + // The Dwarf_info_reader, for reading data. + Dwarf_info_reader* dwinfo_; + // The buffer containing the .debug_ranges section. + const unsigned char* buffer_; + const unsigned char* buffer_end_; + // True if this object owns the buffer and needs to delete it. + bool owns_buffer_; + // The size of a DWARF offset for the current set. + unsigned int offset_size_; + // The current position within the buffer. + const unsigned char* pinfo_; + // TRUE if this is a .debug_pubtypes section. + bool is_pubtypes_; + // For incremental update links, this will hold the offset of the + // input section within the output section. Offsets read from + // relocated data will be relative to the output section, and need + // to be corrected before reading data from the input section. + uint64_t output_section_offset_; + // Fields read from the header. + uint64_t unit_length_; + off_t cu_offset_; + + // Track relocations for this table so we can find the CUs that + // correspond to the subsections. + Elf_reloc_mapper* reloc_mapper_; + // Type of the relocation section (SHT_REL or SHT_RELA). + unsigned int reloc_type_; +}; + +// This class represents a DWARF Debug Info Entry (DIE). + +class Dwarf_die +{ + public: + // An attribute value. + struct Attribute_value + { + unsigned int attr; + unsigned int form; + union + { + int64_t intval; + uint64_t uintval; + const char* stringval; + const unsigned char* blockval; + off_t refval; + } val; + union + { + // Section index for reference forms. + unsigned int shndx; + // Block length for block forms. + unsigned int blocklen; + // Attribute offset for DW_FORM_strp. + unsigned int attr_off; + } aux; + }; + + // A list of attribute values. + typedef std::vector Attributes; + + Dwarf_die(Dwarf_info_reader* dwinfo, + off_t die_offset, + Dwarf_die* parent); + + // Return the DWARF tag for this DIE. + unsigned int + tag() const + { + if (this->abbrev_code_ == NULL) + return 0; + return this->abbrev_code_->tag; + } + + // Return true if this DIE has children. + bool + has_children() const + { + gold_assert(this->abbrev_code_ != NULL); + return this->abbrev_code_->has_children; + } + + // Return true if this DIE has a sibling attribute. + bool + has_sibling_attribute() const + { + gold_assert(this->abbrev_code_ != NULL); + return this->abbrev_code_->has_sibling_attribute; + } + + // Return the value of attribute ATTR. + const Attribute_value* + attribute(unsigned int attr); + + // Return the value of the DW_AT_name attribute. + const char* + name() + { + if (this->name_ == NULL) + this->set_name(); + return this->name_; + } + + // Return the value of the DW_AT_linkage_name + // or DW_AT_MIPS_linkage_name attribute. + const char* + linkage_name() + { + if (this->linkage_name_ == NULL) + this->set_linkage_name(); + return this->linkage_name_; + } + + // Return the value of the DW_AT_specification attribute. + off_t + specification() + { + if (!this->attributes_read_) + this->read_attributes(); + return this->specification_; + } + + // Return the value of the DW_AT_abstract_origin attribute. + off_t + abstract_origin() + { + if (!this->attributes_read_) + this->read_attributes(); + return this->abstract_origin_; + } + + // Return the value of attribute ATTR as a string. + const char* + string_attribute(unsigned int attr); + + // Return the value of attribute ATTR as an integer. + int64_t + int_attribute(unsigned int attr); + + // Return the value of attribute ATTR as an unsigned integer. + uint64_t + uint_attribute(unsigned int attr); + + // Return the value of attribute ATTR as a reference. + off_t + ref_attribute(unsigned int attr, unsigned int* shndx); + + // Return the value of attribute ATTR as a address. + off_t + address_attribute(unsigned int attr, unsigned int* shndx); + + // Return the value of attribute ATTR as a flag. + bool + flag_attribute(unsigned int attr) + { return this->int_attribute(attr) != 0; } + + // Return true if this DIE is a declaration. + bool + is_declaration() + { return this->flag_attribute(elfcpp::DW_AT_declaration); } + + // Return the parent of this DIE. + Dwarf_die* + parent() const + { return this->parent_; } + + // Return the offset of this DIE. + off_t + offset() const + { return this->die_offset_; } + + // Return the offset of this DIE's first child. + off_t + child_offset(); + + // Set the offset of this DIE's next sibling. + void + set_sibling_offset(off_t sibling_offset) + { this->sibling_offset_ = sibling_offset; } + + // Return the offset of this DIE's next sibling. + off_t + sibling_offset(); + + private: + typedef Dwarf_abbrev_table::Abbrev_code Abbrev_code; + + // Read all the attributes of the DIE. + bool + read_attributes(); + + // Set the name of the DIE if present. + void + set_name(); + + // Set the linkage name if present. + void + set_linkage_name(); + + // Skip all the attributes of the DIE and return the offset + // of the next DIE. + off_t + skip_attributes(); + + // The Dwarf_info_reader, for reading attributes. + Dwarf_info_reader* dwinfo_; + // The parent of this DIE. + Dwarf_die* parent_; + // Offset of this DIE within its compilation unit. + off_t die_offset_; + // Offset of the first attribute, relative to the beginning of the DIE. + off_t attr_offset_; + // Offset of the first child, relative to the compilation unit. + off_t child_offset_; + // Offset of the next sibling, relative to the compilation unit. + off_t sibling_offset_; + // The abbreviation table entry. + const Abbrev_code* abbrev_code_; + // The list of attributes. + Attributes attributes_; + // True if the attributes have been read. + bool attributes_read_; + // The following fields hold common attributes to avoid a linear + // search through the attribute list. + // The DIE name (DW_AT_name). + const char* name_; + // Offset of the name in the string table (for DW_FORM_strp). + off_t name_off_; + // The linkage name (DW_AT_linkage_name or DW_AT_MIPS_linkage_name). + const char* linkage_name_; + // Offset of the linkage name in the string table (for DW_FORM_strp). + off_t linkage_name_off_; + // Section index of the string table (for DW_FORM_strp). + unsigned int string_shndx_; + // The value of a DW_AT_specification attribute. + off_t specification_; + // The value of a DW_AT_abstract_origin attribute. + off_t abstract_origin_; +}; + +// This class is used to read the debug info from the .debug_info +// or .debug_types sections. This is a base class that implements +// the generic parsing of the compilation unit header and DIE +// structure. The parse() method parses the entire section, and +// calls the various visit_xxx() methods for each header. Clients +// should derive a new class from this one and implement the +// visit_compilation_unit() and visit_type_unit() functions. + +class Dwarf_info_reader +{ + public: + Dwarf_info_reader(bool is_type_unit, + Relobj* object, + const unsigned char* symtab, + off_t symtab_size, + unsigned int shndx, + unsigned int reloc_shndx, + unsigned int reloc_type) + : is_type_unit_(is_type_unit), object_(object), symtab_(symtab), + symtab_size_(symtab_size), shndx_(shndx), reloc_shndx_(reloc_shndx), + reloc_type_(reloc_type), abbrev_shndx_(0), string_shndx_(0), + buffer_(NULL), buffer_end_(NULL), cu_offset_(0), cu_length_(0), + offset_size_(0), address_size_(0), cu_version_(0), + abbrev_table_(), ranges_table_(this), + reloc_mapper_(NULL), string_buffer_(NULL), string_buffer_end_(NULL), + owns_string_buffer_(false), string_output_section_offset_(0) + { } + + virtual + ~Dwarf_info_reader() + { + if (this->reloc_mapper_ != NULL) + delete this->reloc_mapper_; + if (this->owns_string_buffer_ && this->string_buffer_ != NULL) + delete[] this->string_buffer_; + } + + // Begin parsing the debug info. This calls visit_compilation_unit() + // or visit_type_unit() for each compilation or type unit found in the + // section, and visit_die() for each top-level DIE. + void + parse(); + + // Return the abbrev code entry for a CODE. + const Dwarf_abbrev_table::Abbrev_code* + get_abbrev(unsigned int code) + { return this->abbrev_table_.get_abbrev(code); } + + // Return a pointer to the DWARF info buffer at OFFSET. + const unsigned char* + buffer_at_offset(off_t offset) const + { + const unsigned char* p = this->buffer_ + this->cu_offset_ + offset; + if (this->check_buffer(p + 1)) + return p; + return NULL; + } + + // Read a possibly unaligned integer of SIZE. + template + inline typename elfcpp::Valtype_base::Valtype + read_from_pointer(const unsigned char* source); + + // Read a possibly unaligned integer of SIZE. Update SOURCE after read. + template + inline typename elfcpp::Valtype_base::Valtype + read_from_pointer(const unsigned char** source); + + // Look for a relocation at offset ATTR_OFF in the dwarf info, + // and return the section index and offset of the target. + unsigned int + lookup_reloc(off_t attr_off, off_t* target_off); + + // Return a string from the DWARF string table. + const char* + get_string(off_t str_off, unsigned int string_shndx); + + // Return the size of a DWARF offset. + unsigned int + offset_size() const + { return this->offset_size_; } + + // Return the size of an address. + unsigned int + address_size() const + { return this->address_size_; } + + // Set the section index of the .debug_abbrev section. + // We use this if there are no relocations for the .debug_info section. + // If not set, the code parse() routine will search for the section by name. + void + set_abbrev_shndx(unsigned int abbrev_shndx) + { this->abbrev_shndx_ = abbrev_shndx; } + + // Return a pointer to the object file's ELF symbol table. + const unsigned char* + symtab() const + { return this->symtab_; } + + // Return the size of the object file's ELF symbol table. + off_t + symtab_size() const + { return this->symtab_size_; } + + // Return the offset of the current compilation unit. + off_t + cu_offset() const + { return this->cu_offset_; } + + protected: + // Begin parsing the debug info. This calls visit_compilation_unit() + // or visit_type_unit() for each compilation or type unit found in the + // section, and visit_die() for each top-level DIE. + template + void + do_parse(); + + // The following methods are hooks that are meant to be implemented + // by a derived class. A default, do-nothing, implementation of + // each is provided for this base class. + + // Visit a compilation unit. + virtual void + visit_compilation_unit(off_t cu_offset, off_t cu_length, Dwarf_die* root_die); + + // Visit a type unit. + virtual void + visit_type_unit(off_t tu_offset, off_t type_offset, uint64_t signature, + Dwarf_die* root_die); + + // Read the range table. + Dwarf_range_list* + read_range_list(unsigned int ranges_shndx, off_t ranges_offset) + { + return this->ranges_table_.read_range_list(this->object_, + this->symtab_, + this->symtab_size_, + this->address_size_, + ranges_shndx, + ranges_offset); + } + + // Return the object. + Relobj* + object() const + { return this->object_; } + + // Checkpoint the relocation tracker. + uint64_t + get_reloc_checkpoint() const + { return this->reloc_mapper_->checkpoint(); } + + // Reset the relocation tracker to the CHECKPOINT. + void + reset_relocs(uint64_t checkpoint) + { this->reloc_mapper_->reset(checkpoint); } + + private: + // Print a warning about a corrupt debug section. + void + warn_corrupt_debug_section() const; + + // Check that P is within the bounds of the current section. + bool + check_buffer(const unsigned char* p) const + { + if (p > this->buffer_ + this->cu_offset_ + this->cu_length_) + { + this->warn_corrupt_debug_section(); + return false; + } + return true; + } + + // Read the DWARF string table. + bool + read_string_table(unsigned int string_shndx) + { + // If we've already read this string table, return immediately. + if (this->string_shndx_ > 0 && this->string_shndx_ == string_shndx) + return true; + if (string_shndx == 0 && this->string_shndx_ > 0) + return true; + return this->do_read_string_table(string_shndx); + } + + bool + do_read_string_table(unsigned int string_shndx); + + // True if this is a type unit; false for a compilation unit. + bool is_type_unit_; + // The object containing the .debug_info or .debug_types input section. + Relobj* object_; + // The ELF symbol table. + const unsigned char* symtab_; + // The size of the ELF symbol table. + off_t symtab_size_; + // Index of the .debug_info or .debug_types section. + unsigned int shndx_; + // Index of the relocation section. + unsigned int reloc_shndx_; + // Type of the relocation section (SHT_REL or SHT_RELA). + unsigned int reloc_type_; + // Index of the .debug_abbrev section (0 if not known). + unsigned int abbrev_shndx_; + // Index of the .debug_str section. + unsigned int string_shndx_; + // The buffer for the debug info. + const unsigned char* buffer_; + const unsigned char* buffer_end_; + // Offset of the current compilation unit. + off_t cu_offset_; + // Length of the current compilation unit. + off_t cu_length_; + // Size of a DWARF offset for the current compilation unit. + unsigned int offset_size_; + // Size of an address for the target architecture. + unsigned int address_size_; + // Compilation unit version number. + unsigned int cu_version_; + // Abbreviations table for current compilation unit. + Dwarf_abbrev_table abbrev_table_; + // Ranges table for the current compilation unit. + Dwarf_ranges_table ranges_table_; + // Relocation mapper for the section. + Elf_reloc_mapper* reloc_mapper_; + // The buffer for the debug string table. + const char* string_buffer_; + const char* string_buffer_end_; + // True if this object owns the buffer and needs to delete it. + bool owns_string_buffer_; + // For incremental update links, this will hold the offset of the + // input .debug_str section within the output section. Offsets read + // from relocated data will be relative to the output section, and need + // to be corrected before reading data from the input section. + uint64_t string_output_section_offset_; +}; + +// We can't do better than to keep the offsets in a sorted vector. +// Here, offset is the key, and file_num/line_num is the value. +struct Offset_to_lineno_entry +{ + off_t offset; + int header_num; // which file-list to use (i.e. which .o file are we in) + // A pointer into files_. + unsigned int file_num : sizeof(int) * CHAR_BIT - 1; + // True if this was the last entry for the current offset, meaning + // it's the line that actually applies. + unsigned int last_line_for_offset : 1; + // The line number in the source file. -1 to indicate end-of-function. + int line_num; + + // This sorts by offsets first, and then puts the correct line to + // report for a given offset at the beginning of the run of equal + // offsets (so that asking for 1 line gives the best answer). This + // is not a total ordering. + bool operator<(const Offset_to_lineno_entry& that) const + { + if (this->offset != that.offset) + return this->offset < that.offset; + // Note the '>' which makes this sort 'true' first. + return this->last_line_for_offset > that.last_line_for_offset; + } +}; + +// This class is used to read the line information from the debugging +// section of an object file. + +class Dwarf_line_info +{ + public: + Dwarf_line_info() + { } + + virtual + ~Dwarf_line_info() + { } + + // Given a section number and an offset, returns the associated + // file and line-number, as a string: "file:lineno". If unable + // to do the mapping, returns the empty string. You must call + // read_line_mappings() before calling this function. If + // 'other_lines' is non-NULL, fills that in with other line + // numbers assigned to the same offset. + std::string + addr2line(unsigned int shndx, off_t offset, + std::vector* other_lines) + { return this->do_addr2line(shndx, offset, other_lines); } + + // A helper function for a single addr2line lookup. It also keeps a + // cache of the last CACHE_SIZE Dwarf_line_info objects it created; + // set to 0 not to cache at all. The larger CACHE_SIZE is, the more + // chance this routine won't have to re-create a Dwarf_line_info + // object for its addr2line computation; such creations are slow. + // NOTE: Not thread-safe, so only call from one thread at a time. + static std::string + one_addr2line(Object* object, unsigned int shndx, off_t offset, + size_t cache_size, std::vector* other_lines); + + // This reclaims all the memory that one_addr2line may have cached. + // Use this when you know you will not be calling one_addr2line again. + static void + clear_addr2line_cache(); + + private: + virtual std::string + do_addr2line(unsigned int shndx, off_t offset, + std::vector* other_lines) = 0; +}; + +template +class Sized_dwarf_line_info : public Dwarf_line_info +{ + public: + // Initializes a .debug_line reader for a given object file. + // If SHNDX is specified and non-negative, only read the debug + // information that pertains to the specified section. + Sized_dwarf_line_info(Object* object, unsigned int read_shndx = -1U); + + virtual + ~Sized_dwarf_line_info() + { + if (this->buffer_start_ != NULL) + delete[] this->buffer_start_; + } + + private: + std::string + do_addr2line(unsigned int shndx, off_t offset, + std::vector* other_lines); + + // Formats a file and line number to a string like "dirname/filename:lineno". + std::string + format_file_lineno(const Offset_to_lineno_entry& lineno) const; + + // Start processing line info, and populates the offset_map_. + // If SHNDX is non-negative, only store debug information that + // pertains to the specified section. + void + read_line_mappings(unsigned int shndx); + + // Reads the relocation section associated with .debug_line and + // stores relocation information in reloc_map_. + void + read_relocs(); + + // Reads the DWARF2/3 header for this line info. Each takes as input + // a starting buffer position, and returns the ending position. + const unsigned char* + read_header_prolog(const unsigned char* lineptr); + + const unsigned char* + read_header_tables(const unsigned char* lineptr); + + // Reads the DWARF2/3 line information. If shndx is non-negative, + // discard all line information that doesn't pertain to the given + // section. + const unsigned char* + read_lines(const unsigned char* lineptr, unsigned int shndx); + + // Process a single line info opcode at START using the state + // machine at LSM. Return true if we should define a line using the + // current state of the line state machine. Place the length of the + // opcode in LEN. + bool + process_one_opcode(const unsigned char* start, + struct LineStateMachine* lsm, size_t* len); + + // Some parts of processing differ depending on whether the input + // was a .o file or not. + bool input_is_relobj(); + + // If we saw anything amiss while parsing, we set this to false. + // Then addr2line will always fail (rather than return possibly- + // corrupt data). + bool data_valid_; + + // A DWARF2/3 line info header. This is not the same size as in the + // actual file, as the one in the file may have a 32 bit or 64 bit + // lengths. + + struct Dwarf_line_infoHeader + { + off_t total_length; + int version; + off_t prologue_length; + int min_insn_length; // insn stands for instructin + bool default_is_stmt; // stmt stands for statement + signed char line_base; + int line_range; + unsigned char opcode_base; + std::vector std_opcode_lengths; + int offset_size; + } header_; + + // buffer is the buffer for our line info, starting at exactly where + // the line info to read is. + const unsigned char* buffer_; + const unsigned char* buffer_end_; + // If the buffer was allocated temporarily, and therefore must be + // deallocated in the dtor, this contains a pointer to the start + // of the buffer. + const unsigned char* buffer_start_; + + // This has relocations that point into buffer. + Sized_elf_reloc_mapper* reloc_mapper_; + // The type of the reloc section in track_relocs_--SHT_REL or SHT_RELA. + unsigned int track_relocs_type_; + + // This is used to figure out what section to apply a relocation to. + const unsigned char* symtab_buffer_; + section_size_type symtab_buffer_size_; + + // Holds the directories and files as we see them. We have an array + // of directory-lists, one for each .o file we're reading (usually + // there will just be one, but there may be more if input is a .so). + std::vector > directories_; + // The first part is an index into directories_, the second the filename. + std::vector > > files_; + + // An index into the current directories_ and files_ vectors. + int current_header_index_; + + // A sorted map from offset of the relocation target to the shndx + // and addend for the relocation. + typedef std::map > + Reloc_map; + Reloc_map reloc_map_; + + // We have a vector of offset->lineno entries for every input section. + typedef Unordered_map > + Lineno_map; + + Lineno_map line_number_map_; +}; + +} // End namespace gold. + +#endif // !defined(GOLD_DWARF_READER_H) diff --git a/binutils-2.25/gold/dwp.cc b/binutils-2.25/gold/dwp.cc new file mode 100644 index 00000000..325aa6cc --- /dev/null +++ b/binutils-2.25/gold/dwp.cc @@ -0,0 +1,2224 @@ +// dwp.cc -- DWARF packaging utility + +// Copyright 2012 Free Software Foundation, Inc. +// Written by Cary Coutant . + +// This file is part of dwp, the DWARF packaging utility. + +// 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 "dwp.h" + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "getopt.h" +#include "libiberty.h" +#include "../bfd/bfdver.h" + +#include "elfcpp.h" +#include "elfcpp_file.h" +#include "dirsearch.h" +#include "fileread.h" +#include "object.h" +#include "compressed_output.h" +#include "stringpool.h" +#include "dwarf_reader.h" + +static void +usage(FILE* fd, int) ATTRIBUTE_NORETURN; + +static void +print_version() ATTRIBUTE_NORETURN; + +namespace gold { + +class Dwp_output_file; + +template +class Sized_relobj_dwo; + +// List of .dwo files to process. +typedef std::vector File_list; + +// An input file. +// This class may represent a .dwo file, a .dwp file +// produced by an earlier run, or an executable file whose +// debug section identifies a set of .dwo files to read. + +class Dwo_file +{ + public: + Dwo_file(const char* name) + : name_(name), obj_(NULL), input_file_(NULL), is_compressed_(), + str_offset_map_() + { } + + ~Dwo_file(); + + // Read the input executable file and extract the list of .dwo files + // that it references. + void + read_executable(File_list* files); + + // Read the input file and send its contents to OUTPUT_FILE. + void + read(Dwp_output_file* output_file); + + private: + // Types for mapping input string offsets to output string offsets. + typedef std::pair + Str_offset_map_entry; + typedef std::vector Str_offset_map; + + // A less-than comparison routine for Str_offset_map. + struct Offset_compare + { + bool + operator()(const Str_offset_map_entry& i1, + const Str_offset_map_entry& i2) const + { return i1.first < i2.first; } + }; + + // Create a Sized_relobj_dwo of the given size and endianness, + // and record the target info. P is a pointer to the ELF header + // in memory. + Relobj* + make_object(Dwp_output_file* output_file); + + template + Relobj* + sized_make_object(const unsigned char* p, Input_file* input_file, + Dwp_output_file* output_file); + + // Return the number of sections in the input object file. + unsigned int + shnum() const + { return this->obj_->shnum(); } + + // Return section type. + unsigned int + section_type(unsigned int shndx) + { return this->obj_->section_type(shndx); } + + // Get the name of a section. + std::string + section_name(unsigned int shndx) + { return this->obj_->section_name(shndx); } + + // Return a view of the contents of a section, decompressed if necessary. + // Set *PLEN to the size. Set *IS_NEW to true if the contents need to be + // deleted by the caller. + const unsigned char* + section_contents(unsigned int shndx, section_size_type* plen, bool* is_new) + { return this->obj_->decompressed_section_contents(shndx, plen, is_new); } + + // Read the .debug_cu_index section of a .dwp file, + // and process the CU sets. + void + read_compunit_index(unsigned int, Dwp_output_file*); + + template + void + sized_read_compunit_index(unsigned int, Dwp_output_file*); + + // Read the .debug_tu_index section of a .dwp file, + // and process the TU sets. + void + read_typeunit_index(unsigned int, Dwp_output_file*); + + template + void + sized_read_typeunit_index(unsigned int, Dwp_output_file*); + + // Merge the input string table section into the output file. + void + add_strings(Dwp_output_file*, unsigned int); + + // Copy a section from the input file to the output file. + unsigned int + copy_section(Dwp_output_file* output_file, unsigned int shndx, + const char* section_name, bool is_str_offsets); + + // Remap the string offsets in the .debug_str_offsets.dwo section. + const unsigned char* + remap_str_offsets(const unsigned char* contents, section_size_type len); + + template + const unsigned char* + sized_remap_str_offsets(const unsigned char* contents, section_size_type len); + + // Remap a single string offsets from an offset in the input string table + // to an offset in the output string table. + unsigned int + remap_str_offset(section_offset_type val); + + // Add a set of .debug_info and related sections to OUTPUT_FILE. + void + add_cu_set(Dwp_output_file* output_file, + uint64_t dwo_id, + unsigned int debug_info, + unsigned int debug_abbrev, + unsigned int debug_line, + unsigned int debug_loc, + unsigned int debug_str_offsets, + unsigned int debug_macinfo, + unsigned int debug_macro); + + // Add a set of .debug_types and related sections to OUTPUT_FILE. + void + add_tu_set(Dwp_output_file* output_file, + uint64_t type_sig, + unsigned int debug_types, + unsigned int debug_abbrev, + unsigned int debug_line, + unsigned int debug_str_offsets); + + // The filename. + const char* name_; + // The ELF file, represented as a gold Relobj instance. + Relobj* obj_; + // The Input_file object. + Input_file* input_file_; + // Flags indicating which sections are compressed. + std::vector is_compressed_; + // Map input section index onto output section index. + std::vector shndx_map_; + // Map input string offsets to output string offsets. + Str_offset_map str_offset_map_; +}; + +// An ELF input file. +// We derive from Sized_relobj so that we can use interfaces +// in libgold to access the file. + +template +class Sized_relobj_dwo : public Sized_relobj +{ + public: + typedef typename elfcpp::Elf_types::Elf_Addr Address; + typedef typename Sized_relobj::Symbols Symbols; + + Sized_relobj_dwo(const char* name, Input_file* input_file, + const elfcpp::Ehdr& ehdr) + : Sized_relobj(name, input_file), + elf_file_(this, ehdr) + { } + + ~Sized_relobj_dwo() + { } + + // Setup the section information. + void + setup(); + + protected: + // Return section type. + unsigned int + do_section_type(unsigned int shndx) + { return this->elf_file_.section_type(shndx); } + + // Get the name of a section. + std::string + do_section_name(unsigned int shndx) + { return this->elf_file_.section_name(shndx); } + + // Get the size of a section. + uint64_t + do_section_size(unsigned int shndx) + { return this->elf_file_.section_size(shndx); } + + // Return a view of the contents of a section. + const unsigned char* + do_section_contents(unsigned int, section_size_type*, bool); + + // Return a view of the uncompressed contents of a section. Set *PLEN + // to the size. Set *IS_NEW to true if the contents need to be deleted + // by the caller. + const unsigned char* + do_decompressed_section_contents(unsigned int shndx, + section_size_type* plen, + bool* is_new); + + // The following virtual functions are abstract in the base classes, + // but are not used here. + + // Read the symbols. + void + do_read_symbols(Read_symbols_data*) + { gold_unreachable(); } + + // Lay out the input sections. + void + do_layout(Symbol_table*, Layout*, Read_symbols_data*) + { gold_unreachable(); } + + // Layout sections whose layout was deferred while waiting for + // input files from a plugin. + void + do_layout_deferred_sections(Layout*) + { gold_unreachable(); } + + // Add the symbols to the symbol table. + void + do_add_symbols(Symbol_table*, Read_symbols_data*, Layout*) + { gold_unreachable(); } + + Archive::Should_include + do_should_include_member(Symbol_table*, Layout*, Read_symbols_data*, + std::string*) + { gold_unreachable(); } + + // Iterate over global symbols, calling a visitor class V for each. + void + do_for_all_global_symbols(Read_symbols_data*, + Library_base::Symbol_visitor_base*) + { gold_unreachable(); } + + // Return section flags. + uint64_t + do_section_flags(unsigned int) + { gold_unreachable(); } + + // Return section entsize. + uint64_t + do_section_entsize(unsigned int) + { gold_unreachable(); } + + // Return section address. + uint64_t + do_section_address(unsigned int) + { gold_unreachable(); } + + // Return the section link field. + unsigned int + do_section_link(unsigned int) + { gold_unreachable(); } + + // Return the section link field. + unsigned int + do_section_info(unsigned int) + { gold_unreachable(); } + + // Return the section alignment. + uint64_t + do_section_addralign(unsigned int) + { gold_unreachable(); } + + // Return the Xindex structure to use. + Xindex* + do_initialize_xindex() + { gold_unreachable(); } + + // Get symbol counts. + void + do_get_global_symbol_counts(const Symbol_table*, size_t*, size_t*) const + { gold_unreachable(); } + + // Get global symbols. + const Symbols* + do_get_global_symbols() const + { return NULL; } + + // Return the value of a local symbol. + uint64_t + do_local_symbol_value(unsigned int, uint64_t) const + { gold_unreachable(); } + + unsigned int + do_local_plt_offset(unsigned int) const + { gold_unreachable(); } + + // Return whether local symbol SYMNDX is a TLS symbol. + bool + do_local_is_tls(unsigned int) const + { gold_unreachable(); } + + // Return the number of local symbols. + unsigned int + do_local_symbol_count() const + { gold_unreachable(); } + + // Return the number of local symbols in the output symbol table. + unsigned int + do_output_local_symbol_count() const + { gold_unreachable(); } + + // Return the file offset for local symbols in the output symbol table. + off_t + do_local_symbol_offset() const + { gold_unreachable(); } + + // Read the relocs. + void + do_read_relocs(Read_relocs_data*) + { gold_unreachable(); } + + // Process the relocs to find list of referenced sections. Used only + // during garbage collection. + void + do_gc_process_relocs(Symbol_table*, Layout*, Read_relocs_data*) + { gold_unreachable(); } + + // Scan the relocs and adjust the symbol table. + void + do_scan_relocs(Symbol_table*, Layout*, Read_relocs_data*) + { gold_unreachable(); } + + // Count the local symbols. + void + do_count_local_symbols(Stringpool_template*, + Stringpool_template*) + { gold_unreachable(); } + + // Finalize the local symbols. + unsigned int + do_finalize_local_symbols(unsigned int, off_t, Symbol_table*) + { gold_unreachable(); } + + // Set the offset where local dynamic symbol information will be stored. + unsigned int + do_set_local_dynsym_indexes(unsigned int) + { gold_unreachable(); } + + // Set the offset where local dynamic symbol information will be stored. + unsigned int + do_set_local_dynsym_offset(off_t) + { gold_unreachable(); } + + // Relocate the input sections and write out the local symbols. + void + do_relocate(const Symbol_table*, const Layout*, Output_file*) + { gold_unreachable(); } + + private: + // General access to the ELF file. + elfcpp::Elf_file elf_file_; +}; + +// The output file. +// This class is responsible for collecting the debug index information +// and writing the .dwp file in ELF format. + +class Dwp_output_file +{ + public: + Dwp_output_file(const char* name) + : name_(name), machine_(0), size_(0), big_endian_(false), osabi_(0), + abiversion_(0), fd_(NULL), next_file_offset_(0), shnum_(1), sections_(), + shoff_(0), shstrndx_(0), have_strings_(false), stringpool_(), + shstrtab_(), cu_index_(), tu_index_(), last_type_sig_(0), + last_tu_slot_(0) + { + this->stringpool_.set_no_zero_null(); + } + + // Record the target info from an input file. + void + record_target_info(const char* name, int machine, int size, bool big_endian, + int osabi, int abiversion); + + // Add a string to the debug strings section. + section_offset_type + add_string(const char* str, size_t len); + + // Add a section to the output file, and return the new section index. + unsigned int + add_section(const char* section_name, const unsigned char* contents, + section_size_type len, int align); + + // Add a set of .debug_info and related sections to the output file. + void + add_cu_set(uint64_t dwo_id, unsigned int debug_info, + unsigned int debug_abbrev, unsigned int debug_line, + unsigned int debug_loc, unsigned int debug_str_offsets, + unsigned int debug_macinfo, unsigned int debug_macro); + + // Lookup a type signature and return TRUE if we have already seen it. + bool + lookup_tu(uint64_t type_sig); + + // Add a set of .debug_types and related sections to the output file. + void + add_tu_set(uint64_t type_sig, unsigned int debug_types, + unsigned int debug_abbrev, unsigned int debug_line, + unsigned int debug_str_offsets); + + // Finalize the file, write the string tables and index sections, + // and close the file. + void + finalize(); + + private: + // Sections in the output file. + struct Section + { + const char* name; + off_t offset; + section_size_type size; + int align; + }; + + // A set of sections for a compilation unit or type unit. + struct Cu_or_tu_set + { + uint64_t signature; + unsigned int debug_info_or_types; + unsigned int debug_abbrev; + unsigned int debug_line; + unsigned int debug_loc; + unsigned int debug_str_offsets; + unsigned int debug_macinfo; + unsigned int debug_macro; + }; + + // The index sections defined by the DWARF Package File Format spec. + class Dwp_index + { + public: + // Vector for the section index pool. + typedef std::vector Shndx_pool; + + Dwp_index() + : capacity_(0), used_(0), hash_table_(NULL), shndx_pool_() + { } + + ~Dwp_index() + { } + + // Find a slot in the hash table for SIGNATURE. Return TRUE + // if the entry already exists. + bool + find_or_add(uint64_t signature, unsigned int* slotp); + + // Enter a CU or TU set at the given SLOT in the hash table. + void + enter_set(unsigned int slot, const Cu_or_tu_set& set); + + // Return the contents of the given SLOT in the hash table of signatures. + uint64_t + hash_table(unsigned int slot) const + { return this->hash_table_[slot]; } + + // Return the contents of the given SLOT in the parallel table of + // shndx pool indexes. + uint32_t + index_table(unsigned int slot) const + { return this->index_table_[slot]; } + + // Return the total number of slots in the hash table. + unsigned int + hash_table_total_slots() const + { return this->capacity_; } + + // Return the number of used slots in the hash table. + unsigned int + hash_table_used_slots() const + { return this->used_; } + + // Return an iterator into the shndx pool. + Shndx_pool::const_iterator + shndx_pool() const + { return this->shndx_pool_.begin(); } + + Shndx_pool::const_iterator + shndx_pool_end() const + { return this->shndx_pool_.end(); } + + // Return the number of entries in the shndx pool. + unsigned int + shndx_pool_size() const + { return this->shndx_pool_.size(); } + + private: + // Initialize the hash table. + void + initialize(); + + // Grow the hash table when we reach 2/3 capacity. + void + grow(); + + // The number of slots in the table, a power of 2 such that + // capacity > 3 * size / 2. + unsigned int capacity_; + // The current number of used slots in the hash table. + unsigned int used_; + // The storage for the hash table of signatures. + uint64_t* hash_table_; + // The storage for the parallel table of shndx pool indexes. + uint32_t* index_table_; + // The pool of section indexes. + Shndx_pool shndx_pool_; + }; // End class Dwp_output_file::Dwp_index. + + // Initialize the output file. + void + initialize(); + + // Write the ELF header. + void + write_ehdr(); + + template + void + sized_write_ehdr(); + + // Write a section header. + void + write_shdr(const char* name, unsigned int type, unsigned int flags, + uint64_t addr, off_t offset, section_size_type sect_size, + unsigned int link, unsigned int info, + unsigned int align, unsigned int ent_size); + + template + void + sized_write_shdr(const char* name, unsigned int type, unsigned int flags, + uint64_t addr, off_t offset, section_size_type sect_size, + unsigned int link, unsigned int info, + unsigned int align, unsigned int ent_size); + + // Write a CU or TU index section. + template + void + write_index(const char* sect_name, const Dwp_index& index); + + // The output filename. + const char* name_; + // ELF header parameters. + int machine_; + int size_; + int big_endian_; + int osabi_; + int abiversion_; + // The output file descriptor. + FILE* fd_; + // Next available file offset. + off_t next_file_offset_; + // The number of sections. + unsigned int shnum_; + // Section table. The first entry is shndx 1. + std::vector
sections_; + // File offset of the section header table. + off_t shoff_; + // Section index of the section string table. + unsigned int shstrndx_; + // TRUE if we have added any strings to the string pool. + bool have_strings_; + // String pool for the output .debug_str.dwo section. + Stringpool stringpool_; + // String pool for the .shstrtab section. + Stringpool shstrtab_; + // The compilation unit index. + Dwp_index cu_index_; + // The type unit index. + Dwp_index tu_index_; + // Cache of the last type signature looked up. + uint64_t last_type_sig_; + // Cache of the slot index for the last type signature. + unsigned int last_tu_slot_; +}; + +// A specialization of Dwarf_info_reader, for reading dwo_names from +// DWARF CUs. + +class Dwo_name_info_reader : public Dwarf_info_reader +{ + public: + Dwo_name_info_reader(Relobj* object, unsigned int shndx) + : Dwarf_info_reader(false, object, NULL, 0, shndx, 0, 0), + files_(NULL) + { } + + ~Dwo_name_info_reader() + { } + + // Get the dwo_names from the DWARF compilation unit DIEs. + void + get_dwo_names(File_list* files) + { + this->files_ = files; + this->parse(); + } + + protected: + // Visit a compilation unit. + virtual void + visit_compilation_unit(off_t cu_offset, off_t cu_length, Dwarf_die*); + + private: + // The list of files to populate. + File_list* files_; +}; + +// A specialization of Dwarf_info_reader, for reading dwo_ids and +// type signatures from DWARF CUs and TUs. + +class Dwo_id_info_reader : public Dwarf_info_reader +{ + public: + Dwo_id_info_reader(bool is_type_unit, + Relobj* object, + unsigned int shndx) + : Dwarf_info_reader(is_type_unit, object, NULL, 0, shndx, 0, 0), + dwo_id_found_(false), dwo_id_(0), type_sig_found_(false), type_sig_(0) + { } + + ~Dwo_id_info_reader() + { } + + // Return the dwo_id from a DWARF compilation unit DIE in *DWO_ID. + bool + get_dwo_id(uint64_t* dwo_id) + { + this->parse(); + if (!this->dwo_id_found_) + return false; + *dwo_id = this->dwo_id_; + return true; + } + + // Return the type signature from a DWARF type unit DIE in *TYPE_SIG. + bool + get_type_sig(uint64_t* type_sig) + { + this->parse(); + if (!this->type_sig_found_) + return false; + *type_sig = this->type_sig_; + return true; + } + + protected: + // Visit a compilation unit. + virtual void + visit_compilation_unit(off_t cu_offset, off_t cu_length, Dwarf_die*); + + // Visit a type unit. + virtual void + visit_type_unit(off_t tu_offset, off_t type_offset, uint64_t signature, + Dwarf_die*); + + private: + // TRUE if we found a dwo_id. + bool dwo_id_found_; + // The dwo_id. + uint64_t dwo_id_; + // TRUE if we found a type signature. + bool type_sig_found_; + // The type signature. + uint64_t type_sig_; +}; + +// Class Sized_relobj_dwo. + +// Setup the section information. + +template +void +Sized_relobj_dwo::setup() +{ + const unsigned int shnum = this->elf_file_.shnum(); + this->set_shnum(shnum); + this->section_offsets().resize(shnum); +} + +// Return a view of the contents of a section. + +template +const unsigned char* +Sized_relobj_dwo::do_section_contents( + unsigned int shndx, + section_size_type* plen, + bool cache) +{ + Object::Location loc(this->elf_file_.section_contents(shndx)); + *plen = convert_to_section_size_type(loc.data_size); + if (*plen == 0) + { + static const unsigned char empty[1] = { '\0' }; + return empty; + } + return this->get_view(loc.file_offset, *plen, true, cache); +} + +// Return a view of the uncompressed contents of a section. Set *PLEN +// to the size. Set *IS_NEW to true if the contents need to be deleted +// by the caller. + +template +const unsigned char* +Sized_relobj_dwo::do_decompressed_section_contents( + unsigned int shndx, + section_size_type* plen, + bool* is_new) +{ + section_size_type buffer_size; + const unsigned char* buffer = this->do_section_contents(shndx, &buffer_size, + false); + + std::string sect_name = this->do_section_name(shndx); + if (!is_prefix_of(".zdebug_", sect_name.c_str())) + { + *plen = buffer_size; + *is_new = false; + return buffer; + } + + section_size_type uncompressed_size = get_uncompressed_size(buffer, + buffer_size); + unsigned char* uncompressed_data = new unsigned char[uncompressed_size]; + if (!decompress_input_section(buffer, + buffer_size, + uncompressed_data, + uncompressed_size)) + this->error(_("could not decompress section %s"), + this->section_name(shndx).c_str()); + *plen = uncompressed_size; + *is_new = true; + return uncompressed_data; +} + +// Class Dwo_file. + +Dwo_file::~Dwo_file() +{ + if (this->obj_ != NULL) + delete this->obj_; + if (this->input_file_ != NULL) + delete this->input_file_; +} + +// Read the input executable file and extract the list of .dwo files +// that it references. + +void +Dwo_file::read_executable(File_list* files) +{ + this->obj_ = this->make_object(NULL); + + unsigned int shnum = this->shnum(); + this->is_compressed_.resize(shnum); + this->shndx_map_.resize(shnum); + + unsigned int debug_info = 0; + unsigned int debug_abbrev = 0; + + // Scan the section table and collect the debug sections we need. + // (Section index 0 is a dummy section; skip it.) + for (unsigned int i = 1; i < shnum; i++) + { + if (this->section_type(i) != elfcpp::SHT_PROGBITS) + continue; + std::string sect_name = this->section_name(i); + const char* suffix = sect_name.c_str(); + if (is_prefix_of(".debug_", suffix)) + suffix += 7; + else if (is_prefix_of(".zdebug_", suffix)) + { + this->is_compressed_[i] = true; + suffix += 8; + } + else + continue; + if (strcmp(suffix, "info") == 0) + debug_info = i; + else if (strcmp(suffix, "abbrev") == 0) + debug_abbrev = i; + } + + if (debug_info > 0) + { + Dwo_name_info_reader dwarf_reader(this->obj_, debug_info); + dwarf_reader.set_abbrev_shndx(debug_abbrev); + dwarf_reader.get_dwo_names(files); + } +} + +// Read the input file and send its contents to OUTPUT_FILE. + +void +Dwo_file::read(Dwp_output_file* output_file) +{ + this->obj_ = this->make_object(output_file); + + unsigned int shnum = this->shnum(); + this->is_compressed_.resize(shnum); + this->shndx_map_.resize(shnum); + + typedef std::vector Types_list; + Types_list debug_types; + unsigned int debug_info = 0; + unsigned int debug_abbrev = 0; + unsigned int debug_line = 0; + unsigned int debug_loc = 0; + unsigned int debug_str = 0; + unsigned int debug_str_offsets = 0; + unsigned int debug_macinfo = 0; + unsigned int debug_macro = 0; + unsigned int debug_cu_index = 0; + unsigned int debug_tu_index = 0; + + // Scan the section table and look for .dwp index sections. + // (Section index 0 is a dummy section; skip it.) + for (unsigned int i = 1; i < shnum; i++) + { + if (this->section_type(i) != elfcpp::SHT_PROGBITS) + continue; + std::string sect_name = this->section_name(i); + const char* suffix = sect_name.c_str(); + if (is_prefix_of(".debug_", suffix)) + suffix += 7; + else if (is_prefix_of(".zdebug_", suffix)) + { + this->is_compressed_[i] = true; + suffix += 8; + } + else + continue; + if (strcmp(suffix, "cu_index") == 0) + debug_cu_index = i; + else if (strcmp(suffix, "tu_index") == 0) + debug_tu_index = i; + else if (strcmp(suffix, "str.dwo") == 0) + debug_str = i; + } + + // Merge the input string table into the output string table. + this->add_strings(output_file, debug_str); + + // If we found any .dwp index sections, read those and add the section + // sets to the output file. + if (debug_cu_index > 0 || debug_tu_index > 0) + { + if (debug_cu_index > 0) + this->read_compunit_index(debug_cu_index, output_file); + if (debug_tu_index > 0) + this->read_typeunit_index(debug_tu_index, output_file); + return; + } + + // If we found no index sections, this is a .dwo file. + // Scan the section table and collect the debug sections. + for (unsigned int i = 1; i < shnum; i++) + { + if (this->section_type(i) != elfcpp::SHT_PROGBITS) + continue; + std::string sect_name = this->section_name(i); + const char* suffix = sect_name.c_str(); + if (is_prefix_of(".debug_", suffix)) + suffix += 7; + else if (is_prefix_of(".zdebug_", suffix)) + suffix += 8; + else + continue; + // TODO: Check for one of each section (except .debug_types). + if (strcmp(suffix, "info.dwo") == 0) + debug_info = i; + else if (strcmp(suffix, "types.dwo") == 0) + debug_types.push_back(i); + else if (strcmp(suffix, "abbrev.dwo") == 0) + debug_abbrev = i; + else if (strcmp(suffix, "line.dwo") == 0) + debug_line = i; + else if (strcmp(suffix, "loc.dwo") == 0) + debug_loc = i; + else if (strcmp(suffix, "str_offsets.dwo") == 0) + debug_str_offsets = i; + else if (strcmp(suffix, "macinfo.dwo") == 0) + debug_macinfo = i; + else if (strcmp(suffix, "macro.dwo") == 0) + debug_macro = i; + } + + if (debug_info > 0) + { + // Extract the dwo_id from .debug_info.dwo section. + uint64_t dwo_id; + Dwo_id_info_reader dwarf_reader(false, this->obj_, debug_info); + dwarf_reader.set_abbrev_shndx(debug_abbrev); + if (!dwarf_reader.get_dwo_id(&dwo_id)) + gold_fatal(_("%s: .debug_info.dwo section does not have DW_AT_GNU_dwo_id " + "attribute"), this->name_); + this->add_cu_set(output_file, dwo_id, debug_info, debug_abbrev, + debug_line, debug_loc, debug_str_offsets, + debug_macinfo, debug_macro); + } + + for (Types_list::const_iterator tp = debug_types.begin(); + tp != debug_types.end(); + ++tp) + { + // Extract the type signature from .debug_types.dwo section. + uint64_t type_sig; + gold_assert(*tp > 0); + Dwo_id_info_reader dwarf_reader(true, this->obj_, *tp); + dwarf_reader.set_abbrev_shndx(debug_abbrev); + if (!dwarf_reader.get_type_sig(&type_sig)) + gold_fatal(_("%s: .debug_types.dwo section does not have type signature"), + this->name_); + this->add_tu_set(output_file, type_sig, *tp, debug_abbrev, debug_line, + debug_str_offsets); + } +} + +// Create a Sized_relobj_dwo of the given size and endianness, +// and record the target info. + +Relobj* +Dwo_file::make_object(Dwp_output_file* output_file) +{ + // Open the input file. + Input_file* input_file = new Input_file(this->name_); + this->input_file_ = input_file; + Dirsearch dirpath; + int index; + if (!input_file->open(dirpath, NULL, &index)) + gold_fatal(_("%s: can't open"), this->name_); + + // Check that it's an ELF file. + off_t filesize = input_file->file().filesize(); + int hdrsize = elfcpp::Elf_recognizer::max_header_size; + if (filesize < hdrsize) + hdrsize = filesize; + const unsigned char* elf_header = + input_file->file().get_view(0, 0, hdrsize, true, false); + if (!elfcpp::Elf_recognizer::is_elf_file(elf_header, hdrsize)) + gold_fatal(_("%s: not an ELF object file"), this->name_); + + // Get the size, endianness, machine, etc. info from the header, + // make an appropriately-sized Relobj, and pass the target info + // to the output object. + int size; + bool big_endian; + std::string error; + if (!elfcpp::Elf_recognizer::is_valid_header(elf_header, hdrsize, &size, + &big_endian, &error)) + gold_fatal(_("%s: %s"), this->name_, error.c_str()); + + if (size == 32) + { + if (big_endian) +#ifdef HAVE_TARGET_32_BIG + return this->sized_make_object<32, true>(elf_header, input_file, + output_file); +#else + gold_unreachable(); +#endif + else +#ifdef HAVE_TARGET_32_LITTLE + return this->sized_make_object<32, false>(elf_header, input_file, + output_file); +#else + gold_unreachable(); +#endif + } + else if (size == 64) + { + if (big_endian) +#ifdef HAVE_TARGET_64_BIG + return this->sized_make_object<64, true>(elf_header, input_file, + output_file); +#else + gold_unreachable(); +#endif + else +#ifdef HAVE_TARGET_64_LITTLE + return this->sized_make_object<64, false>(elf_header, input_file, + output_file); +#else + gold_unreachable(); +#endif + } + else + gold_unreachable(); +} + +// Function template to create a Sized_relobj_dwo and record the target info. +// P is a pointer to the ELF header in memory. + +template +Relobj* +Dwo_file::sized_make_object(const unsigned char* p, Input_file* input_file, + Dwp_output_file* output_file) +{ + elfcpp::Ehdr ehdr(p); + Sized_relobj_dwo* obj = + new Sized_relobj_dwo(this->name_, input_file, ehdr); + obj->setup(); + if (output_file != NULL) + output_file->record_target_info( + this->name_, ehdr.get_e_machine(), size, big_endian, + ehdr.get_e_ident()[elfcpp::EI_OSABI], + ehdr.get_e_ident()[elfcpp::EI_ABIVERSION]); + return obj; +} + +// Read the .debug_cu_index section of a .dwp file, +// and process the CU sets. + +void +Dwo_file::read_compunit_index(unsigned int shndx, Dwp_output_file* output_file) +{ + if (this->obj_->is_big_endian()) + this->sized_read_compunit_index(shndx, output_file); + else + this->sized_read_compunit_index(shndx, output_file); +} + +template +void +Dwo_file::sized_read_compunit_index(unsigned int shndx, + Dwp_output_file* output_file) +{ + section_size_type len; + bool is_new; + const unsigned char* contents = this->section_contents(shndx, &len, &is_new); + + unsigned int version = + elfcpp::Swap_unaligned<32, big_endian>::readval(contents); + if (version != 1) + gold_fatal(_("%s: .debug_cu_index has unsupported version number %d"), + this->name_, version); + + unsigned int nused = + elfcpp::Swap_unaligned<32, big_endian>::readval(contents + + 2 * sizeof(uint32_t)); + if (nused == 0) + return; + + unsigned int nslots = + elfcpp::Swap_unaligned<32, big_endian>::readval(contents + + 3 * sizeof(uint32_t)); + + const unsigned char* phash = contents + 4 * sizeof(uint32_t); + const unsigned char* pindex = phash + nslots * sizeof(uint64_t); + const unsigned char* shndx_pool = pindex + nslots * sizeof(uint32_t); + const unsigned char* limit = contents + len; + + if (shndx_pool >= limit) + gold_fatal(_("%s: .debug_cu_index is corrupt"), this->name_); + + // Loop over the slots of the hash table. + for (unsigned int i = 0; i < nslots; ++i) + { + uint64_t dwo_id = + elfcpp::Swap_unaligned<64, big_endian>::readval(phash); + if (dwo_id != 0) + { + unsigned int index = + elfcpp::Swap_unaligned<32, big_endian>::readval(pindex); + const unsigned char* shndx_list = + shndx_pool + index * sizeof(uint32_t); + + // Collect the debug sections for this compilation unit set. + unsigned int debug_info = 0; + unsigned int debug_abbrev = 0; + unsigned int debug_line = 0; + unsigned int debug_loc = 0; + unsigned int debug_str_offsets = 0; + unsigned int debug_macinfo = 0; + unsigned int debug_macro = 0; + for (;;) + { + if (shndx_list >= limit) + gold_fatal(_("%s: .debug_cu_index is corrupt"), + this->name_); + unsigned int shndx = + elfcpp::Swap_unaligned<32, big_endian>::readval(shndx_list); + if (shndx == 0) + break; + if (shndx > this->shnum()) + gold_fatal(_("%s: .debug_cu_index has bad shndx"), + this->name_); + std::string sect_name = this->section_name(shndx); + const char* suffix = sect_name.c_str(); + if (is_prefix_of(".debug_", suffix)) + suffix += 7; + else if (is_prefix_of(".zdebug_", suffix)) + suffix += 8; + else + gold_fatal(_("%s: .debug_cu_index refers to " + "non-debug section"), this->name_); + if (strcmp(suffix, "info.dwo") == 0) + debug_info = shndx; + else if (strcmp(suffix, "abbrev.dwo") == 0) + debug_abbrev = shndx; + else if (strcmp(suffix, "line.dwo") == 0) + debug_line = shndx; + else if (strcmp(suffix, "loc.dwo") == 0) + debug_loc = shndx; + else if (strcmp(suffix, "str_offsets.dwo") == 0) + debug_str_offsets = shndx; + else if (strcmp(suffix, "macinfo.dwo") == 0) + debug_macinfo = shndx; + else if (strcmp(suffix, "macro.dwo") == 0) + debug_macro = shndx; + shndx_list += sizeof(uint32_t); + } + this->add_cu_set(output_file, dwo_id, debug_info, debug_abbrev, + debug_line, debug_loc, debug_str_offsets, + debug_macinfo, debug_macro); + } + phash += sizeof(uint64_t); + pindex += sizeof(uint32_t); + } + + if (is_new) + delete[] contents; +} + +// Read the .debug_tu_index section of a .dwp file, +// and process the TU sets. + +void +Dwo_file::read_typeunit_index(unsigned int shndx, Dwp_output_file* output_file) +{ + if (this->obj_->is_big_endian()) + this->sized_read_typeunit_index(shndx, output_file); + else + this->sized_read_typeunit_index(shndx, output_file); +} + +template +void +Dwo_file::sized_read_typeunit_index(unsigned int shndx, + Dwp_output_file* output_file) +{ + section_size_type len; + bool is_new; + const unsigned char* contents = this->section_contents(shndx, &len, &is_new); + + unsigned int version = + elfcpp::Swap_unaligned<32, big_endian>::readval(contents); + if (version != 1) + gold_fatal(_("%s: .debug_tu_index has unsupported version number %d"), + this->name_, version); + + unsigned int nused = + elfcpp::Swap_unaligned<32, big_endian>::readval(contents + + 2 * sizeof(uint32_t)); + if (nused == 0) + return; + + unsigned int nslots = + elfcpp::Swap_unaligned<32, big_endian>::readval(contents + + 3 * sizeof(uint32_t)); + + const unsigned char* phash = contents + 4 * sizeof(uint32_t); + const unsigned char* pindex = phash + nslots * sizeof(uint64_t); + const unsigned char* shndx_pool = pindex + nslots * sizeof(uint32_t); + const unsigned char* limit = contents + len; + + if (shndx_pool >= limit) + gold_fatal(_("%s: .debug_tu_index is corrupt"), this->name_); + + // Loop over the slots of the hash table. + for (unsigned int i = 0; i < nslots; ++i) + { + uint64_t type_sig = + elfcpp::Swap_unaligned<64, big_endian>::readval(phash); + if (type_sig != 0) + { + unsigned int index = + elfcpp::Swap_unaligned<32, big_endian>::readval(pindex); + const unsigned char* shndx_list = + shndx_pool + index * sizeof(uint32_t); + + // Collect the debug sections for this type unit set. + unsigned int debug_types = 0; + unsigned int debug_abbrev = 0; + unsigned int debug_line = 0; + unsigned int debug_str_offsets = 0; + for (;;) + { + if (shndx_list >= limit) + gold_fatal(_("%s: .debug_tu_index is corrupt"), + this->name_); + unsigned int shndx = + elfcpp::Swap_unaligned<32, big_endian>::readval(shndx_list); + if (shndx == 0) + break; + if (shndx > this->shnum()) + gold_fatal(_("%s: .debug_tu_index has bad shndx"), + this->name_); + std::string sect_name = this->section_name(shndx); + const char* suffix = sect_name.c_str(); + if (is_prefix_of(".debug_", suffix)) + suffix += 7; + else if (is_prefix_of(".zdebug_", suffix)) + suffix += 8; + else + gold_fatal(_("%s: .debug_tu_index refers to " + "non-debug section"), this->name_); + if (strcmp(suffix, "types.dwo") == 0) + debug_types = shndx; + else if (strcmp(suffix, "abbrev.dwo") == 0) + debug_abbrev = shndx; + else if (strcmp(suffix, "line.dwo") == 0) + debug_line = shndx; + else if (strcmp(suffix, "str_offsets.dwo") == 0) + debug_str_offsets = shndx; + shndx_list += sizeof(uint32_t); + } + this->add_tu_set(output_file, type_sig, debug_types, debug_abbrev, + debug_line, debug_str_offsets); + } + phash += sizeof(uint64_t); + pindex += sizeof(uint32_t); + } + + if (is_new) + delete[] contents; +} + +// Merge the input string table section into the output file. + +void +Dwo_file::add_strings(Dwp_output_file* output_file, unsigned int debug_str) +{ + section_size_type len; + bool is_new; + const unsigned char* pdata = this->section_contents(debug_str, &len, &is_new); + const char* p = reinterpret_cast(pdata); + const char* pend = p + len; + + // Check that the last string is null terminated. + if (pend[-1] != '\0') + gold_fatal(_("%s: last entry in string section '%s' " + "is not null terminated"), + this->name_, + this->section_name(debug_str).c_str()); + + // Count the number of strings in the section, and size the map. + size_t count = 0; + for (const char* pt = p; pt < pend; pt += strlen(pt) + 1) + ++count; + this->str_offset_map_.reserve(count + 1); + + // Add the strings to the output string table, and record the new offsets + // in the map. + section_offset_type i = 0; + section_offset_type new_offset; + while (p < pend) + { + size_t len = strlen(p); + new_offset = output_file->add_string(p, len); + this->str_offset_map_.push_back(std::make_pair(i, new_offset)); + p += len + 1; + i += len + 1; + } + new_offset = 0; + this->str_offset_map_.push_back(std::make_pair(i, new_offset)); + if (is_new) + delete[] pdata; +} + +// Copy a section from the input file to the output file. +// If IS_STR_OFFSETS is true, remap the string offsets for the +// output string table. + +unsigned int +Dwo_file::copy_section(Dwp_output_file* output_file, unsigned int shndx, + const char* section_name, bool is_str_offsets) +{ + // Some sections may be referenced from more than one set. + // Don't copy a section more than once. + if (this->shndx_map_[shndx] > 0) + return this->shndx_map_[shndx]; + + section_size_type len; + bool is_new; + const unsigned char* contents = this->section_contents(shndx, &len, &is_new); + + if (is_str_offsets) + { + const unsigned char* remapped = this->remap_str_offsets(contents, len); + if (is_new) + delete[] contents; + contents = remapped; + is_new = true; + } + + this->shndx_map_[shndx] = output_file->add_section(section_name, contents, + len, 1); + if (is_new) + delete[] contents; + + return this->shndx_map_[shndx]; +} + +// Remap the +const unsigned char* +Dwo_file::remap_str_offsets(const unsigned char* contents, + section_size_type len) +{ + if ((len & 3) != 0) + gold_fatal(_("%s: .debug_str_offsets.dwo section size not a multiple of 4"), + this->name_); + + if (this->obj_->is_big_endian()) + return this->sized_remap_str_offsets(contents, len); + else + return this->sized_remap_str_offsets(contents, len); +} + +template +const unsigned char* +Dwo_file::sized_remap_str_offsets(const unsigned char* contents, + section_size_type len) +{ + unsigned char* remapped = new unsigned char[len]; + const unsigned char* p = contents; + unsigned char* q = remapped; + while (len > 0) + { + unsigned int val = elfcpp::Swap_unaligned<32, big_endian>::readval(p); + val = this->remap_str_offset(val); + elfcpp::Swap_unaligned<32, big_endian>::writeval(q, val); + len -= 4; + p += 4; + q += 4; + } + return remapped; +} + +unsigned int +Dwo_file::remap_str_offset(section_offset_type val) +{ + Str_offset_map_entry entry; + entry.first = val; + + Str_offset_map::const_iterator p = + std::lower_bound(this->str_offset_map_.begin(), + this->str_offset_map_.end(), + entry, Offset_compare()); + + if (p == this->str_offset_map_.end() || p->first > val) + { + if (p == this->str_offset_map_.begin()) + return 0; + --p; + gold_assert(p->first <= val); + } + + return p->second + (val - p->first); +} + +// Add a set of .debug_info and related sections to OUTPUT_FILE. + +void +Dwo_file::add_cu_set(Dwp_output_file* output_file, + uint64_t dwo_id, + unsigned int debug_info, + unsigned int debug_abbrev, + unsigned int debug_line, + unsigned int debug_loc, + unsigned int debug_str_offsets, + unsigned int debug_macinfo, + unsigned int debug_macro) +{ + if (debug_info == 0) + gold_fatal(_("%s: no .debug_info.dwo section found"), this->name_); + if (debug_abbrev == 0) + gold_fatal(_("%s: no .debug_abbrev.dwo section found"), this->name_); + + debug_abbrev = this->copy_section(output_file, debug_abbrev, + ".debug_abbrev.dwo", false); + if (debug_line > 0) + debug_line = this->copy_section(output_file, debug_line, + ".debug_line.dwo", false); + if (debug_loc > 0) + debug_loc = this->copy_section(output_file, debug_loc, ".debug_loc.dwo", + false); + if (debug_macinfo > 0) + debug_macinfo = this->copy_section(output_file, debug_macinfo, + ".debug_macinfo.dwo", false); + if (debug_macro > 0) + debug_macro = this->copy_section(output_file, debug_macro, + ".debug_macro.dwo", false); + + if (debug_str_offsets > 0) + debug_str_offsets = this->copy_section(output_file, debug_str_offsets, + ".debug_str_offsets.dwo", true); + + debug_info = this->copy_section(output_file, debug_info, ".debug_info.dwo", + false); + + output_file->add_cu_set(dwo_id, debug_info, debug_abbrev, debug_line, + debug_loc, debug_str_offsets, debug_macinfo, + debug_macro); +} + +// Add a set of .debug_types and related sections to OUTPUT_FILE. + +void +Dwo_file::add_tu_set(Dwp_output_file* output_file, + uint64_t type_sig, + unsigned int debug_types, + unsigned int debug_abbrev, + unsigned int debug_line, + unsigned int debug_str_offsets) +{ + if (debug_types == 0) + gold_fatal(_("%s: no .debug_types.dwo section found"), this->name_); + if (debug_abbrev == 0) + gold_fatal(_("%s: no .debug_abbrev.dwo section found"), this->name_); + + // Ignore duplicate type signatures. + if (output_file->lookup_tu(type_sig)) + return; + + debug_abbrev = this->copy_section(output_file, debug_abbrev, + ".debug_abbrev.dwo", false); + if (debug_line > 0) + debug_line = this->copy_section(output_file, debug_line, + ".debug_line.dwo", false); + + if (debug_str_offsets > 0) + debug_str_offsets = this->copy_section(output_file, debug_str_offsets, + ".debug_str_offsets.dwo", true); + + debug_types = this->copy_section(output_file, debug_types, + ".debug_types.dwo", false); + + output_file->add_tu_set(type_sig, debug_types, debug_abbrev, debug_line, + debug_str_offsets); +} + +// Class Dwp_output_file. + +// Record the target info from an input file. On first call, we +// set the ELF header values for the output file. On subsequent +// calls, we just verify that the values match. + +void +Dwp_output_file::record_target_info(const char*, int machine, + int size, bool big_endian, + int osabi, int abiversion) +{ + // TODO: Check the values on subsequent calls. + if (this->size_ > 0) + return; + + this->machine_ = machine; + this->size_ = size; + this->big_endian_ = big_endian; + this->osabi_ = osabi; + this->abiversion_ = abiversion; + + if (size == 32) + this->next_file_offset_ = elfcpp::Elf_sizes<32>::ehdr_size; + else if (size == 64) + this->next_file_offset_ = elfcpp::Elf_sizes<64>::ehdr_size; + else + gold_unreachable(); + + this->fd_ = ::fopen(this->name_, "wb"); + if (this->fd_ == NULL) + gold_fatal(_("%s: %s"), this->name_, strerror(errno)); + + // Write zeroes for the ELF header initially. We'll write + // the actual header during finalize(). + static const char buf[elfcpp::Elf_sizes<64>::ehdr_size] = { 0 }; + if (::fwrite(buf, 1, this->next_file_offset_, this->fd_) + < (size_t) this->next_file_offset_) + gold_fatal(_("%s: %s"), this->name_, strerror(errno)); +} + +// Add a string to the debug strings section. + +section_offset_type +Dwp_output_file::add_string(const char* str, size_t len) +{ + Stringpool::Key key; + this->stringpool_.add_with_length(str, len, true, &key); + this->have_strings_ = true; + // We aren't supposed to call get_offset() until after + // calling set_string_offsets(), but the offsets will + // not change unless optimizing the string pool. + return this->stringpool_.get_offset_from_key(key); +} + +// Align the file offset to the given boundary. + +static inline off_t +align_offset(off_t off, int align) +{ + return (off + align - 1) & ~(align - 1); +} + +// Add a section to the output file, and return the new section index. + +unsigned int +Dwp_output_file::add_section(const char* section_name, + const unsigned char* contents, + section_size_type len, + int align) +{ + off_t file_offset = this->next_file_offset_; + gold_assert(this->size_ > 0 && file_offset > 0); + + file_offset = align_offset(file_offset, align); + + ::fseek(this->fd_, file_offset, SEEK_SET); + if (::fwrite(contents, 1, len, this->fd_) < len) + gold_fatal(_("%s: error writing section '%s'"), this->name_, section_name); + + section_name = this->shstrtab_.add_with_length(section_name, + strlen(section_name), + false, NULL); + Section sect = { section_name, file_offset, len, align }; + this->sections_.push_back(sect); + + this->next_file_offset_ = file_offset + len; + return this->shnum_++; +} + +// Add a set of .debug_info and related sections to the output file. + +void +Dwp_output_file::add_cu_set(uint64_t dwo_id, + unsigned int debug_info, + unsigned int debug_abbrev, + unsigned int debug_line, + unsigned int debug_loc, + unsigned int debug_str_offsets, + unsigned int debug_macinfo, + unsigned int debug_macro) +{ + Cu_or_tu_set cu_set = { dwo_id, debug_info, debug_abbrev, debug_line, + debug_loc, debug_str_offsets, debug_macinfo, + debug_macro }; + unsigned int slot; + if (!this->cu_index_.find_or_add(dwo_id, &slot)) + this->cu_index_.enter_set(slot, cu_set); + else + gold_warning(_("%s: duplicate entry for CU (dwo_id 0x%llx)"), + this->name_, (unsigned long long)dwo_id); +} + +// Lookup a type signature and return TRUE if we have already seen it. +bool +Dwp_output_file::lookup_tu(uint64_t type_sig) +{ + this->last_type_sig_ = type_sig; + return this->tu_index_.find_or_add(type_sig, &this->last_tu_slot_); +} + +// Add a set of .debug_types and related sections to the output file. + +void +Dwp_output_file::add_tu_set(uint64_t type_sig, + unsigned int debug_types, + unsigned int debug_abbrev, + unsigned int debug_line, + unsigned int debug_str_offsets) +{ + Cu_or_tu_set tu_set = { type_sig, debug_types, debug_abbrev, debug_line, + 0, debug_str_offsets, 0, 0 }; + unsigned int slot; + if (type_sig == this->last_type_sig_) + slot = this->last_tu_slot_; + else + this->tu_index_.find_or_add(type_sig, &slot); + this->tu_index_.enter_set(slot, tu_set); +} + +// Find a slot in the hash table for SIGNATURE. Return TRUE +// if the entry already exists. + +bool +Dwp_output_file::Dwp_index::find_or_add(uint64_t signature, + unsigned int* slotp) +{ + if (this->capacity_ == 0) + this->initialize(); + unsigned int slot = + static_cast(signature) & (this->capacity_ - 1); + unsigned int secondary_hash; + uint64_t probe = this->hash_table_[slot]; + if (probe != 0 && probe != signature) + { + secondary_hash = (static_cast(signature >> 32) + & (this->capacity_ - 1)) | 1; + do + { + slot = (slot + secondary_hash) & (this->capacity_ - 1); + probe = this->hash_table_[slot]; + } while (probe != 0 && probe != signature); + } + *slotp = slot; + return (probe != 0); +} + +// Enter a CU or TU set at the given SLOT in the hash table. + +void +Dwp_output_file::Dwp_index::enter_set(unsigned int slot, + const Cu_or_tu_set& set) +{ + gold_assert(slot < this->capacity_); + gold_assert(set.debug_info_or_types > 0); + gold_assert(set.debug_abbrev > 0); + + // Add the section indexes to the pool. + uint32_t pool_index = this->shndx_pool_.size(); + this->shndx_pool_.push_back(set.debug_info_or_types); + this->shndx_pool_.push_back(set.debug_abbrev); + if (set.debug_line > 0) + this->shndx_pool_.push_back(set.debug_line); + if (set.debug_loc > 0) + this->shndx_pool_.push_back(set.debug_loc); + if (set.debug_str_offsets > 0) + this->shndx_pool_.push_back(set.debug_str_offsets); + if (set.debug_macinfo > 0) + this->shndx_pool_.push_back(set.debug_macinfo); + if (set.debug_macro > 0) + this->shndx_pool_.push_back(set.debug_macro); + this->shndx_pool_.push_back(0); + + // Enter the signature and pool index into the hash table. + gold_assert(this->hash_table_[slot] == 0); + this->hash_table_[slot] = set.signature; + this->index_table_[slot] = pool_index; + ++this->used_; + + // Grow the hash table when we exceed 2/3 capacity. + if (this->used_ * 3 > this->capacity_ * 2) + this->grow(); +} + +// Initialize the hash table. + +void +Dwp_output_file::Dwp_index::initialize() +{ + this->capacity_ = 16; + this->hash_table_ = new uint64_t[this->capacity_]; + memset(this->hash_table_, 0, this->capacity_ * sizeof(uint64_t)); + this->index_table_ = new uint32_t[this->capacity_]; + memset(this->index_table_, 0, this->capacity_ * sizeof(uint32_t)); +} + +// Grow the hash table when we reach 2/3 capacity. + +void +Dwp_output_file::Dwp_index::grow() +{ + unsigned int old_capacity = this->capacity_; + uint64_t* old_hash_table = this->hash_table_; + uint32_t* old_index_table = this->index_table_; + unsigned int old_used = this->used_; + + this->capacity_ = old_capacity * 2; + this->hash_table_ = new uint64_t[this->capacity_]; + memset(this->hash_table_, 0, this->capacity_ * sizeof(uint64_t)); + this->index_table_ = new uint32_t[this->capacity_]; + memset(this->index_table_, 0, this->capacity_ * sizeof(uint32_t)); + this->used_ = 0; + + for (unsigned int i = 0; i < old_capacity; ++i) + { + uint64_t signature = old_hash_table[i]; + if (signature != 0) + { + unsigned int slot; + bool found = this->find_or_add(signature, &slot); + gold_assert(!found); + this->hash_table_[slot] = signature; + this->index_table_[slot] = old_index_table[i]; + ++this->used_; + } + } + gold_assert(this->used_ == old_used); + + delete[] old_hash_table; + delete[] old_index_table; +} + +// Initialize the output file. + +void +Dwp_output_file::initialize() +{ + // We can't initialize the output file until we've recorded the + // target info from the first input file. + gold_assert(this->size_ > 0); +} + +// Finalize the file, write the string tables and index sections, +// and close the file. + +void +Dwp_output_file::finalize() +{ + unsigned char* buf; + + // Write the debug string table. + if (this->have_strings_) + { + this->stringpool_.set_string_offsets(); + section_size_type len = this->stringpool_.get_strtab_size(); + buf = new unsigned char[len]; + this->stringpool_.write_to_buffer(buf, len); + this->add_section(".debug_str.dwo", buf, len, 1); + delete[] buf; + } + + // Write the CU and TU indexes. + if (this->big_endian_) + { + this->write_index(".debug_cu_index", this->cu_index_); + this->write_index(".debug_tu_index", this->tu_index_); + } + else + { + this->write_index(".debug_cu_index", this->cu_index_); + this->write_index(".debug_tu_index", this->tu_index_); + } + + off_t file_offset = this->next_file_offset_; + + // Write the section string table. + this->shstrndx_ = this->shnum_++; + const char* shstrtab_name = + this->shstrtab_.add_with_length(".shstrtab", + sizeof(".shstrtab") - 1, + false, NULL); + this->shstrtab_.set_string_offsets(); + section_size_type shstrtab_len = this->shstrtab_.get_strtab_size(); + buf = new unsigned char[shstrtab_len]; + this->shstrtab_.write_to_buffer(buf, shstrtab_len); + off_t shstrtab_off = file_offset; + ::fseek(this->fd_, file_offset, 0); + if (::fwrite(buf, 1, shstrtab_len, this->fd_) < shstrtab_len) + gold_fatal(_("%s: error writing section '.shstrtab'"), this->name_); + delete[] buf; + file_offset += shstrtab_len; + + // Write the section header table. The first entry is a NULL entry. + // This is followed by the debug sections, and finally we write the + // .shstrtab section header. + file_offset = align_offset(file_offset, this->size_ == 32 ? 4 : 8); + this->shoff_ = file_offset; + ::fseek(this->fd_, file_offset, 0); + section_size_type sh0_size = 0; + unsigned int sh0_link = 0; + if (this->shnum_ >= elfcpp::SHN_LORESERVE) + sh0_size = this->shnum_; + if (this->shstrndx_ >= elfcpp::SHN_LORESERVE) + sh0_link = this->shstrndx_; + this->write_shdr(NULL, 0, 0, 0, 0, sh0_size, sh0_link, 0, 0, 0); + for (unsigned int i = 0; i < this->sections_.size(); ++i) + { + Section& sect = this->sections_[i]; + this->write_shdr(sect.name, elfcpp::SHT_PROGBITS, 0, 0, sect.offset, + sect.size, 0, 0, sect.align, 0); + } + this->write_shdr(shstrtab_name, elfcpp::SHT_STRTAB, 0, 0, + shstrtab_off, shstrtab_len, 0, 0, 1, 0); + + // Write the ELF header. + this->write_ehdr(); + + // Close the file. + if (this->fd_ != NULL) + { + if (::fclose(this->fd_) != 0) + gold_fatal(_("%s: %s"), this->name_, strerror(errno)); + } + this->fd_ = NULL; +} + +// Write a CU or TU index section. +template +void +Dwp_output_file::write_index(const char* sect_name, const Dwp_index& index) +{ + const unsigned int nslots = index.hash_table_total_slots(); + const unsigned int nused = index.hash_table_used_slots(); + const unsigned int npool = index.shndx_pool_size(); + const section_size_type index_size = (4 * sizeof(uint32_t) + + nslots * sizeof(uint64_t) + + nslots * sizeof(uint32_t) + + npool * sizeof(uint32_t)); + + // Allocate a buffer for the section contents. + unsigned char* buf = new unsigned char[index_size]; + unsigned char* p = buf; + + // Write the section header: version number, padding, + // number of used slots and total number of slots. + elfcpp::Swap_unaligned<32, big_endian>::writeval(p, 1); + p += sizeof(uint32_t); + elfcpp::Swap_unaligned<32, big_endian>::writeval(p, 0); + p += sizeof(uint32_t); + elfcpp::Swap_unaligned<32, big_endian>::writeval(p, nused); + p += sizeof(uint32_t); + elfcpp::Swap_unaligned<32, big_endian>::writeval(p, nslots); + p += sizeof(uint32_t); + + // Write the hash table. + for (unsigned int i = 0; i < nslots; ++i) + { + elfcpp::Swap_unaligned<64, big_endian>::writeval(p, index.hash_table(i)); + p += sizeof(uint64_t); + } + + // Write the parallel index table. + for (unsigned int i = 0; i < nslots; ++i) + { + elfcpp::Swap_unaligned<32, big_endian>::writeval(p, index.index_table(i)); + p += sizeof(uint32_t); + } + + // Write the section index pool. + Dwp_index::Shndx_pool::const_iterator pool = index.shndx_pool(); + for (unsigned int i = 0; i < npool; ++i) + { + gold_assert(pool != index.shndx_pool_end()); + elfcpp::Swap_unaligned<32, big_endian>::writeval(p, *pool); + p += sizeof(uint32_t); + ++pool; + } + + gold_assert(p == buf + index_size); + + this->add_section(sect_name, buf, index_size, sizeof(uint64_t)); + + delete[] buf; +} + +// Write the ELF header. + +void +Dwp_output_file::write_ehdr() +{ + if (this->size_ == 32) + { + if (this->big_endian_) + return this->sized_write_ehdr<32, true>(); + else + return this->sized_write_ehdr<32, false>(); + } + else if (this->size_ == 64) + { + if (this->big_endian_) + return this->sized_write_ehdr<64, true>(); + else + return this->sized_write_ehdr<64, false>(); + } + else + gold_unreachable(); +} + +template +void +Dwp_output_file::sized_write_ehdr() +{ + const unsigned int ehdr_size = elfcpp::Elf_sizes::ehdr_size; + unsigned char buf[ehdr_size]; + elfcpp::Ehdr_write ehdr(buf); + + unsigned char e_ident[elfcpp::EI_NIDENT]; + memset(e_ident, 0, elfcpp::EI_NIDENT); + e_ident[elfcpp::EI_MAG0] = elfcpp::ELFMAG0; + e_ident[elfcpp::EI_MAG1] = elfcpp::ELFMAG1; + e_ident[elfcpp::EI_MAG2] = elfcpp::ELFMAG2; + e_ident[elfcpp::EI_MAG3] = elfcpp::ELFMAG3; + if (size == 32) + e_ident[elfcpp::EI_CLASS] = elfcpp::ELFCLASS32; + else if (size == 64) + e_ident[elfcpp::EI_CLASS] = elfcpp::ELFCLASS64; + else + gold_unreachable(); + e_ident[elfcpp::EI_DATA] = (big_endian + ? elfcpp::ELFDATA2MSB + : elfcpp::ELFDATA2LSB); + e_ident[elfcpp::EI_VERSION] = elfcpp::EV_CURRENT; + ehdr.put_e_ident(e_ident); + + ehdr.put_e_type(elfcpp::ET_REL); + ehdr.put_e_machine(this->machine_); + ehdr.put_e_version(elfcpp::EV_CURRENT); + ehdr.put_e_entry(0); + ehdr.put_e_phoff(0); + ehdr.put_e_shoff(this->shoff_); + ehdr.put_e_flags(0); + ehdr.put_e_ehsize(elfcpp::Elf_sizes::ehdr_size); + ehdr.put_e_phentsize(0); + ehdr.put_e_phnum(0); + ehdr.put_e_shentsize(elfcpp::Elf_sizes::shdr_size); + ehdr.put_e_shnum(this->shnum_ < elfcpp::SHN_LORESERVE ? this->shnum_ : 0); + ehdr.put_e_shstrndx(this->shstrndx_ < elfcpp::SHN_LORESERVE + ? this->shstrndx_ + : static_cast(elfcpp::SHN_XINDEX)); + + ::fseek(this->fd_, 0, 0); + if (::fwrite(buf, 1, ehdr_size, this->fd_) < ehdr_size) + gold_fatal(_("%s: error writing ELF header"), this->name_); +} + +// Write a section header. + +void +Dwp_output_file::write_shdr(const char* name, unsigned int type, + unsigned int flags, uint64_t addr, off_t offset, + section_size_type sect_size, unsigned int link, + unsigned int info, unsigned int align, + unsigned int ent_size) +{ + if (this->size_ == 32) + { + if (this->big_endian_) + return this->sized_write_shdr<32, true>(name, type, flags, addr, + offset, sect_size, link, info, + align, ent_size); + else + return this->sized_write_shdr<32, false>(name, type, flags, addr, + offset, sect_size, link, info, + align, ent_size); + } + else if (this->size_ == 64) + { + if (this->big_endian_) + return this->sized_write_shdr<64, true>(name, type, flags, addr, + offset, sect_size, link, info, + align, ent_size); + else + return this->sized_write_shdr<64, false>(name, type, flags, addr, + offset, sect_size, link, info, + align, ent_size); + } + else + gold_unreachable(); +} + +template +void +Dwp_output_file::sized_write_shdr(const char* name, unsigned int type, + unsigned int flags, uint64_t addr, + off_t offset, section_size_type sect_size, + unsigned int link, unsigned int info, + unsigned int align, unsigned int ent_size) +{ + const unsigned int shdr_size = elfcpp::Elf_sizes::shdr_size; + unsigned char buf[shdr_size]; + elfcpp::Shdr_write shdr(buf); + + shdr.put_sh_name(name == NULL ? 0 : this->shstrtab_.get_offset(name)); + shdr.put_sh_type(type); + shdr.put_sh_flags(flags); + shdr.put_sh_addr(addr); + shdr.put_sh_offset(offset); + shdr.put_sh_size(sect_size); + shdr.put_sh_link(link); + shdr.put_sh_info(info); + shdr.put_sh_addralign(align); + shdr.put_sh_entsize(ent_size); + if (::fwrite(buf, 1, shdr_size, this->fd_) < shdr_size) + gold_fatal(_("%s: error writing section header table"), this->name_); +} + +// Class Dwo_name_info_reader. + +// Visit a compilation unit. + +void +Dwo_name_info_reader::visit_compilation_unit(off_t, off_t, Dwarf_die* die) +{ + const char* dwo_name = die->string_attribute(elfcpp::DW_AT_GNU_dwo_name); + if (dwo_name != NULL) + this->files_->push_back(dwo_name); +} + +// Class Dwo_id_info_reader. + +// Visit a compilation unit. + +void +Dwo_id_info_reader::visit_compilation_unit(off_t, off_t, Dwarf_die* die) +{ + this->dwo_id_ = die->uint_attribute(elfcpp::DW_AT_GNU_dwo_id); + if (this->dwo_id_ != 0) + this->dwo_id_found_ = true; +} + +// Visit a type unit. + +void +Dwo_id_info_reader::visit_type_unit(off_t, off_t, uint64_t signature, + Dwarf_die*) +{ + this->type_sig_ = signature; + this->type_sig_found_ = true; +} + +}; // End namespace gold + +using namespace gold; + +// Options. + +struct option dwp_options[] = + { + { "exec", required_argument, NULL, 'e' }, + { "help", no_argument, NULL, 'h' }, + { "output", required_argument, NULL, 'o' }, + { "verbose", no_argument, NULL, 'v' }, + { "version", no_argument, NULL, 'V' }, + { NULL, 0, NULL, 0 } + }; + +// Print usage message and exit. + +static void +usage(FILE* fd, int exit_status) +{ + fprintf(fd, _("Usage: %s [options] [file...]\n"), program_name); + fprintf(fd, _(" -h, --help Print this help message\n")); + fprintf(fd, _(" -e EXE, --exec EXE Get list of dwo files from EXE" + " (defaults output to EXE.dwp)\n")); + fprintf(fd, _(" -o FILE, --output FILE Set output dwp file name\n")); + fprintf(fd, _(" -v, --verbose Verbose output\n")); + fprintf(fd, _(" -V, --version Print version number\n")); + + // REPORT_BUGS_TO is defined in bfd/bfdver.h. + const char* report = REPORT_BUGS_TO; + if (*report != '\0') + fprintf(fd, _("\nReport bugs to %s\n"), report); + exit(exit_status); +} + +// Report version information. + +static void +print_version() +{ + // This output is intended to follow the GNU standards. + printf("GNU dwp %s\n", BFD_VERSION_STRING); + printf(_("Copyright 2012 Free Software Foundation, Inc.\n")); + printf(_("\ +This program is free software; you may redistribute it under the terms of\n\ +the GNU General Public License version 3 or (at your option) any later version.\n\ +This program has absolutely no warranty.\n")); + exit(EXIT_SUCCESS); +} + +// Main program. + +int +main(int argc, char** argv) +{ +#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES) + setlocale(LC_MESSAGES, ""); +#endif +#if defined (HAVE_SETLOCALE) + setlocale(LC_CTYPE, ""); +#endif + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + program_name = argv[0]; + + // Initialize the global parameters, to let random code get to the + // errors object. + Errors errors(program_name); + set_parameters_errors(&errors); + + // Initialize gold's global options. We don't use these in + // this program, but they need to be initialized so that + // functions we call from libgold work properly. + General_options options; + set_parameters_options(&options); + + // In libiberty; expands @filename to the args in "filename". + expandargv(&argc, &argv); + + // Collect file names and options. + File_list files; + std::string output_filename; + const char* exe_filename = NULL; + bool verbose = false; + int c; + while ((c = getopt_long(argc, argv, "e:ho:vV", dwp_options, NULL)) != -1) + { + switch (c) + { + case 'h': + usage(stdout, EXIT_SUCCESS); + case 'e': + exe_filename = optarg; + break; + case 'o': + output_filename.assign(optarg); + break; + case 'v': + verbose = true; + break; + case 'V': + print_version(); + case '?': + default: + usage(stderr, EXIT_FAILURE); + } + } + + if (output_filename.empty()) + { + if (exe_filename == NULL) + gold_fatal(_("no output file specified")); + output_filename.assign(exe_filename); + output_filename.append(".dwp"); + } + + Dwp_output_file output_file(output_filename.c_str()); + + // Get list of .dwo files from the executable. + if (exe_filename != NULL) + { + Dwo_file exe_file(exe_filename); + exe_file.read_executable(&files); + } + + // Add any additional files listed on command line. + for (int i = optind; i < argc; ++i) + files.push_back(argv[i]); + + if (exe_filename == NULL && files.empty()) + gold_fatal(_("no input files and no executable specified")); + + // Process each file, adding its contents to the output file. + for (File_list::const_iterator f = files.begin(); f != files.end(); ++f) + { + if (verbose) + fprintf(stderr, "%s\n", f->c_str()); + Dwo_file dwo_file(f->c_str()); + dwo_file.read(&output_file); + } + + output_file.finalize(); + + return EXIT_SUCCESS; +} diff --git a/binutils-2.25/gold/dwp.h b/binutils-2.25/gold/dwp.h new file mode 100644 index 00000000..25d4f680 --- /dev/null +++ b/binutils-2.25/gold/dwp.h @@ -0,0 +1,120 @@ +// dwp.h -- general definitions for dwp. + +// Copyright 2012 Free Software Foundation, Inc. +// Written by Cary Coutant . + +// This file is part of dwp, the DWARF packaging utility. + +// 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. + +#ifndef DWP_DWP_H +#define DWP_DWP_H 1 + +#include "config.h" +#include "ansidecl.h" + +#include +#include +#include +#include +#include + +#include "system.h" + +namespace gold +{ + +extern const char* program_name; + +class General_options; +class Command_line; +class Dirsearch; +class Input_objects; +class Mapfile; +class Symbol; +class Symbol_table; +class Layout; +class Task; +class Workqueue; +class Output_file; +template +struct Relocate_info; + +// The size of a section if we are going to look at the contents. +typedef size_t section_size_type; + +// An offset within a section when we are looking at the contents. +typedef ptrdiff_t section_offset_type; + +inline bool +is_prefix_of(const char* prefix, const char* str) +{ + return strncmp(prefix, str, strlen(prefix)) == 0; +} + +// Exit status codes. + +enum Exit_status +{ + GOLD_OK = EXIT_SUCCESS, + GOLD_ERR = EXIT_FAILURE, + GOLD_FALLBACK = EXIT_FAILURE + 1 +}; + +// This function is called to exit the program. Status is true to +// exit success (0) and false to exit failure (1). +extern void +gold_exit(Exit_status status) ATTRIBUTE_NORETURN; + +// This function is called to emit an error message and then +// immediately exit with failure. +extern void +gold_fatal(const char* format, ...) ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF_1; + +// This function is called to issue a warning. +extern void +gold_warning(const char* msg, ...) ATTRIBUTE_PRINTF_1; + +#define gold_unreachable() \ + (gold::do_gold_unreachable(__FILE__, __LINE__, \ + static_cast(__FUNCTION__))) + +extern void do_gold_unreachable(const char*, int, const char*) + ATTRIBUTE_NORETURN; + +// Assertion check. + +#define gold_assert(expr) ((void)(!(expr) ? gold_unreachable(), 0 : 0)) + +// Convert numeric types without unnoticed loss of precision. +template +inline To +convert_types(const From from) +{ + To to = from; + gold_assert(static_cast(to) == from); + return to; +} + +// A common case of convert_types<>: convert to section_size_type. +template +inline section_size_type +convert_to_section_size_type(const From from) +{ return convert_types(from); } + +}; // End namespace gold. + +#endif // !defined(DWP_DWP_H) diff --git a/binutils-2.25/gold/dynobj.cc b/binutils-2.25/gold/dynobj.cc new file mode 100644 index 00000000..ac0c321c --- /dev/null +++ b/binutils-2.25/gold/dynobj.cc @@ -0,0 +1,1970 @@ +// dynobj.cc -- dynamic object support for gold + +// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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 +#include + +#include "elfcpp.h" +#include "parameters.h" +#include "script.h" +#include "symtab.h" +#include "dynobj.h" + +namespace gold +{ + +// Class Dynobj. + +// Sets up the default soname_ to use, in the (rare) cases we never +// see a DT_SONAME entry. + +Dynobj::Dynobj(const std::string& name, Input_file* input_file, off_t offset) + : Object(name, input_file, true, offset), + needed_(), + unknown_needed_(UNKNOWN_NEEDED_UNSET) +{ + // This will be overridden by a DT_SONAME entry, hopefully. But if + // we never see a DT_SONAME entry, our rule is to use the dynamic + // object's filename. The only exception is when the dynamic object + // is part of an archive (so the filename is the archive's + // filename). In that case, we use just the dynobj's name-in-archive. + if (input_file == NULL) + this->soname_ = name; + else + { + this->soname_ = input_file->found_name(); + if (this->offset() != 0) + { + std::string::size_type open_paren = this->name().find('('); + std::string::size_type close_paren = this->name().find(')'); + if (open_paren != std::string::npos + && close_paren != std::string::npos) + { + // It's an archive, and name() is of the form 'foo.a(bar.so)'. + open_paren += 1; + this->soname_ = this->name().substr(open_paren, + close_paren - open_paren); + } + } + } +} + +// Class Sized_dynobj. + +template +Sized_dynobj::Sized_dynobj( + const std::string& name, + Input_file* input_file, + off_t offset, + const elfcpp::Ehdr& ehdr) + : Dynobj(name, input_file, offset), + elf_file_(this, ehdr), + dynsym_shndx_(-1U), + symbols_(NULL), + defined_count_(0) +{ +} + +// Set up the object. + +template +void +Sized_dynobj::setup() +{ + const unsigned int shnum = this->elf_file_.shnum(); + this->set_shnum(shnum); +} + +// Find the SHT_DYNSYM section and the various version sections, and +// the dynamic section, given the section headers. + +template +void +Sized_dynobj::find_dynsym_sections( + const unsigned char* pshdrs, + unsigned int* pversym_shndx, + unsigned int* pverdef_shndx, + unsigned int* pverneed_shndx, + unsigned int* pdynamic_shndx) +{ + *pversym_shndx = -1U; + *pverdef_shndx = -1U; + *pverneed_shndx = -1U; + *pdynamic_shndx = -1U; + + unsigned int symtab_shndx = 0; + unsigned int xindex_shndx = 0; + unsigned int xindex_link = 0; + const unsigned int shnum = this->shnum(); + const unsigned char* p = pshdrs; + for (unsigned int i = 0; i < shnum; ++i, p += This::shdr_size) + { + typename This::Shdr shdr(p); + + unsigned int* pi; + switch (shdr.get_sh_type()) + { + case elfcpp::SHT_DYNSYM: + this->dynsym_shndx_ = i; + if (xindex_shndx > 0 && xindex_link == i) + { + Xindex* xindex = new Xindex(this->elf_file_.large_shndx_offset()); + xindex->read_symtab_xindex(this, xindex_shndx, + pshdrs); + this->set_xindex(xindex); + } + pi = NULL; + break; + case elfcpp::SHT_SYMTAB: + symtab_shndx = i; + pi = NULL; + break; + case elfcpp::SHT_GNU_versym: + pi = pversym_shndx; + break; + case elfcpp::SHT_GNU_verdef: + pi = pverdef_shndx; + break; + case elfcpp::SHT_GNU_verneed: + pi = pverneed_shndx; + break; + case elfcpp::SHT_DYNAMIC: + pi = pdynamic_shndx; + break; + case elfcpp::SHT_SYMTAB_SHNDX: + xindex_shndx = i; + xindex_link = this->adjust_shndx(shdr.get_sh_link()); + if (xindex_link == this->dynsym_shndx_) + { + Xindex* xindex = new Xindex(this->elf_file_.large_shndx_offset()); + xindex->read_symtab_xindex(this, xindex_shndx, + pshdrs); + this->set_xindex(xindex); + } + pi = NULL; + break; + default: + pi = NULL; + break; + } + + if (pi == NULL) + continue; + + if (*pi != -1U) + this->error(_("unexpected duplicate type %u section: %u, %u"), + shdr.get_sh_type(), *pi, i); + + *pi = i; + } + + // If there is no dynamic symbol table, use the normal symbol table. + // On some SVR4 systems, a shared library is stored in an archive. + // The version stored in the archive only has a normal symbol table. + // It has an SONAME entry which points to another copy in the file + // system which has a dynamic symbol table as usual. This is way of + // addressing the issues which glibc addresses using GROUP with + // libc_nonshared.a. + if (this->dynsym_shndx_ == -1U && symtab_shndx != 0) + { + this->dynsym_shndx_ = symtab_shndx; + if (xindex_shndx > 0 && xindex_link == symtab_shndx) + { + Xindex* xindex = new Xindex(this->elf_file_.large_shndx_offset()); + xindex->read_symtab_xindex(this, xindex_shndx, + pshdrs); + this->set_xindex(xindex); + } + } +} + +// Read the contents of section SHNDX. PSHDRS points to the section +// headers. TYPE is the expected section type. LINK is the expected +// section link. Store the data in *VIEW and *VIEW_SIZE. The +// section's sh_info field is stored in *VIEW_INFO. + +template +void +Sized_dynobj::read_dynsym_section( + const unsigned char* pshdrs, + unsigned int shndx, + elfcpp::SHT type, + unsigned int link, + File_view** view, + section_size_type* view_size, + unsigned int* view_info) +{ + if (shndx == -1U) + { + *view = NULL; + *view_size = 0; + *view_info = 0; + return; + } + + typename This::Shdr shdr(pshdrs + shndx * This::shdr_size); + + gold_assert(shdr.get_sh_type() == type); + + if (this->adjust_shndx(shdr.get_sh_link()) != link) + this->error(_("unexpected link in section %u header: %u != %u"), + shndx, this->adjust_shndx(shdr.get_sh_link()), link); + + *view = this->get_lasting_view(shdr.get_sh_offset(), shdr.get_sh_size(), + true, false); + *view_size = convert_to_section_size_type(shdr.get_sh_size()); + *view_info = shdr.get_sh_info(); +} + +// Read the dynamic tags. Set the soname field if this shared object +// has a DT_SONAME tag. Record the DT_NEEDED tags. PSHDRS points to +// the section headers. DYNAMIC_SHNDX is the section index of the +// SHT_DYNAMIC section. STRTAB_SHNDX, STRTAB, and STRTAB_SIZE are the +// section index and contents of a string table which may be the one +// associated with the SHT_DYNAMIC section. + +template +void +Sized_dynobj::read_dynamic(const unsigned char* pshdrs, + unsigned int dynamic_shndx, + unsigned int strtab_shndx, + const unsigned char* strtabu, + off_t strtab_size) +{ + typename This::Shdr dynamicshdr(pshdrs + dynamic_shndx * This::shdr_size); + gold_assert(dynamicshdr.get_sh_type() == elfcpp::SHT_DYNAMIC); + + const off_t dynamic_size = dynamicshdr.get_sh_size(); + const unsigned char* pdynamic = this->get_view(dynamicshdr.get_sh_offset(), + dynamic_size, true, false); + + const unsigned int link = this->adjust_shndx(dynamicshdr.get_sh_link()); + if (link != strtab_shndx) + { + if (link >= this->shnum()) + { + this->error(_("DYNAMIC section %u link out of range: %u"), + dynamic_shndx, link); + return; + } + + typename This::Shdr strtabshdr(pshdrs + link * This::shdr_size); + if (strtabshdr.get_sh_type() != elfcpp::SHT_STRTAB) + { + this->error(_("DYNAMIC section %u link %u is not a strtab"), + dynamic_shndx, link); + return; + } + + strtab_size = strtabshdr.get_sh_size(); + strtabu = this->get_view(strtabshdr.get_sh_offset(), strtab_size, false, + false); + } + + const char* const strtab = reinterpret_cast(strtabu); + + for (const unsigned char* p = pdynamic; + p < pdynamic + dynamic_size; + p += This::dyn_size) + { + typename This::Dyn dyn(p); + + switch (dyn.get_d_tag()) + { + case elfcpp::DT_NULL: + // We should always see DT_NULL at the end of the dynamic + // tags. + return; + + case elfcpp::DT_SONAME: + { + off_t val = dyn.get_d_val(); + if (val >= strtab_size) + this->error(_("DT_SONAME value out of range: %lld >= %lld"), + static_cast(val), + static_cast(strtab_size)); + else + this->set_soname_string(strtab + val); + } + break; + + case elfcpp::DT_NEEDED: + { + off_t val = dyn.get_d_val(); + if (val >= strtab_size) + this->error(_("DT_NEEDED value out of range: %lld >= %lld"), + static_cast(val), + static_cast(strtab_size)); + else + this->add_needed(strtab + val); + } + break; + + default: + break; + } + } + + this->error(_("missing DT_NULL in dynamic segment")); +} + +// Read the symbols and sections from a dynamic object. We read the +// dynamic symbols, not the normal symbols. + +template +void +Sized_dynobj::do_read_symbols(Read_symbols_data* sd) +{ + this->read_section_data(&this->elf_file_, sd); + + const unsigned char* const pshdrs = sd->section_headers->data(); + + unsigned int versym_shndx; + unsigned int verdef_shndx; + unsigned int verneed_shndx; + unsigned int dynamic_shndx; + this->find_dynsym_sections(pshdrs, &versym_shndx, &verdef_shndx, + &verneed_shndx, &dynamic_shndx); + + unsigned int strtab_shndx = -1U; + + sd->symbols = NULL; + sd->symbols_size = 0; + sd->external_symbols_offset = 0; + sd->symbol_names = NULL; + sd->symbol_names_size = 0; + sd->versym = NULL; + sd->versym_size = 0; + sd->verdef = NULL; + sd->verdef_size = 0; + sd->verdef_info = 0; + sd->verneed = NULL; + sd->verneed_size = 0; + sd->verneed_info = 0; + + if (this->dynsym_shndx_ != -1U) + { + // Get the dynamic symbols. + typename This::Shdr dynsymshdr(pshdrs + + this->dynsym_shndx_ * This::shdr_size); + + sd->symbols = this->get_lasting_view(dynsymshdr.get_sh_offset(), + dynsymshdr.get_sh_size(), true, + false); + sd->symbols_size = + convert_to_section_size_type(dynsymshdr.get_sh_size()); + + // Get the symbol names. + strtab_shndx = this->adjust_shndx(dynsymshdr.get_sh_link()); + if (strtab_shndx >= this->shnum()) + { + this->error(_("invalid dynamic symbol table name index: %u"), + strtab_shndx); + return; + } + typename This::Shdr strtabshdr(pshdrs + strtab_shndx * This::shdr_size); + if (strtabshdr.get_sh_type() != elfcpp::SHT_STRTAB) + { + this->error(_("dynamic symbol table name section " + "has wrong type: %u"), + static_cast(strtabshdr.get_sh_type())); + return; + } + + sd->symbol_names = this->get_lasting_view(strtabshdr.get_sh_offset(), + strtabshdr.get_sh_size(), + false, false); + sd->symbol_names_size = + convert_to_section_size_type(strtabshdr.get_sh_size()); + + // Get the version information. + + unsigned int dummy; + this->read_dynsym_section(pshdrs, versym_shndx, elfcpp::SHT_GNU_versym, + this->dynsym_shndx_, + &sd->versym, &sd->versym_size, &dummy); + + // We require that the version definition and need section link + // to the same string table as the dynamic symbol table. This + // is not a technical requirement, but it always happens in + // practice. We could change this if necessary. + + this->read_dynsym_section(pshdrs, verdef_shndx, elfcpp::SHT_GNU_verdef, + strtab_shndx, &sd->verdef, &sd->verdef_size, + &sd->verdef_info); + + this->read_dynsym_section(pshdrs, verneed_shndx, elfcpp::SHT_GNU_verneed, + strtab_shndx, &sd->verneed, &sd->verneed_size, + &sd->verneed_info); + } + + // Read the SHT_DYNAMIC section to find whether this shared object + // has a DT_SONAME tag and to record any DT_NEEDED tags. This + // doesn't really have anything to do with reading the symbols, but + // this is a convenient place to do it. + if (dynamic_shndx != -1U) + this->read_dynamic(pshdrs, dynamic_shndx, strtab_shndx, + (sd->symbol_names == NULL + ? NULL + : sd->symbol_names->data()), + sd->symbol_names_size); +} + +// Return the Xindex structure to use for object with lots of +// sections. + +template +Xindex* +Sized_dynobj::do_initialize_xindex() +{ + gold_assert(this->dynsym_shndx_ != -1U); + Xindex* xindex = new Xindex(this->elf_file_.large_shndx_offset()); + xindex->initialize_symtab_xindex(this, this->dynsym_shndx_); + return xindex; +} + +// Lay out the input sections for a dynamic object. We don't want to +// include sections from a dynamic object, so all that we actually do +// here is check for .gnu.warning and .note.GNU-split-stack sections. + +template +void +Sized_dynobj::do_layout(Symbol_table* symtab, + Layout*, + Read_symbols_data* sd) +{ + const unsigned int shnum = this->shnum(); + if (shnum == 0) + return; + + // Get the section headers. + const unsigned char* pshdrs = sd->section_headers->data(); + + // Get the section names. + const unsigned char* pnamesu = sd->section_names->data(); + const char* pnames = reinterpret_cast(pnamesu); + + // Skip the first, dummy, section. + pshdrs += This::shdr_size; + for (unsigned int i = 1; i < shnum; ++i, pshdrs += This::shdr_size) + { + typename This::Shdr shdr(pshdrs); + + if (shdr.get_sh_name() >= sd->section_names_size) + { + this->error(_("bad section name offset for section %u: %lu"), + i, static_cast(shdr.get_sh_name())); + return; + } + + const char* name = pnames + shdr.get_sh_name(); + + this->handle_gnu_warning_section(name, i, symtab); + this->handle_split_stack_section(name); + } + + delete sd->section_headers; + sd->section_headers = NULL; + delete sd->section_names; + sd->section_names = NULL; +} + +// Add an entry to the vector mapping version numbers to version +// strings. + +template +void +Sized_dynobj::set_version_map( + Version_map* version_map, + unsigned int ndx, + const char* name) const +{ + if (ndx >= version_map->size()) + version_map->resize(ndx + 1); + if ((*version_map)[ndx] != NULL) + this->error(_("duplicate definition for version %u"), ndx); + (*version_map)[ndx] = name; +} + +// Add mappings for the version definitions to VERSION_MAP. + +template +void +Sized_dynobj::make_verdef_map( + Read_symbols_data* sd, + Version_map* version_map) const +{ + if (sd->verdef == NULL) + return; + + const char* names = reinterpret_cast(sd->symbol_names->data()); + section_size_type names_size = sd->symbol_names_size; + + const unsigned char* pverdef = sd->verdef->data(); + section_size_type verdef_size = sd->verdef_size; + const unsigned int count = sd->verdef_info; + + const unsigned char* p = pverdef; + for (unsigned int i = 0; i < count; ++i) + { + elfcpp::Verdef verdef(p); + + if (verdef.get_vd_version() != elfcpp::VER_DEF_CURRENT) + { + this->error(_("unexpected verdef version %u"), + verdef.get_vd_version()); + return; + } + + const section_size_type vd_ndx = verdef.get_vd_ndx(); + + // The GNU linker clears the VERSYM_HIDDEN bit. I'm not + // sure why. + + // The first Verdaux holds the name of this version. Subsequent + // ones are versions that this one depends upon, which we don't + // care about here. + const section_size_type vd_cnt = verdef.get_vd_cnt(); + if (vd_cnt < 1) + { + this->error(_("verdef vd_cnt field too small: %u"), + static_cast(vd_cnt)); + return; + } + + const section_size_type vd_aux = verdef.get_vd_aux(); + if ((p - pverdef) + vd_aux >= verdef_size) + { + this->error(_("verdef vd_aux field out of range: %u"), + static_cast(vd_aux)); + return; + } + + const unsigned char* pvda = p + vd_aux; + elfcpp::Verdaux verdaux(pvda); + + const section_size_type vda_name = verdaux.get_vda_name(); + if (vda_name >= names_size) + { + this->error(_("verdaux vda_name field out of range: %u"), + static_cast(vda_name)); + return; + } + + this->set_version_map(version_map, vd_ndx, names + vda_name); + + const section_size_type vd_next = verdef.get_vd_next(); + if ((p - pverdef) + vd_next >= verdef_size) + { + this->error(_("verdef vd_next field out of range: %u"), + static_cast(vd_next)); + return; + } + + p += vd_next; + } +} + +// Add mappings for the required versions to VERSION_MAP. + +template +void +Sized_dynobj::make_verneed_map( + Read_symbols_data* sd, + Version_map* version_map) const +{ + if (sd->verneed == NULL) + return; + + const char* names = reinterpret_cast(sd->symbol_names->data()); + section_size_type names_size = sd->symbol_names_size; + + const unsigned char* pverneed = sd->verneed->data(); + const section_size_type verneed_size = sd->verneed_size; + const unsigned int count = sd->verneed_info; + + const unsigned char* p = pverneed; + for (unsigned int i = 0; i < count; ++i) + { + elfcpp::Verneed verneed(p); + + if (verneed.get_vn_version() != elfcpp::VER_NEED_CURRENT) + { + this->error(_("unexpected verneed version %u"), + verneed.get_vn_version()); + return; + } + + const section_size_type vn_aux = verneed.get_vn_aux(); + + if ((p - pverneed) + vn_aux >= verneed_size) + { + this->error(_("verneed vn_aux field out of range: %u"), + static_cast(vn_aux)); + return; + } + + const unsigned int vn_cnt = verneed.get_vn_cnt(); + const unsigned char* pvna = p + vn_aux; + for (unsigned int j = 0; j < vn_cnt; ++j) + { + elfcpp::Vernaux vernaux(pvna); + + const unsigned int vna_name = vernaux.get_vna_name(); + if (vna_name >= names_size) + { + this->error(_("vernaux vna_name field out of range: %u"), + static_cast(vna_name)); + return; + } + + this->set_version_map(version_map, vernaux.get_vna_other(), + names + vna_name); + + const section_size_type vna_next = vernaux.get_vna_next(); + if ((pvna - pverneed) + vna_next >= verneed_size) + { + this->error(_("verneed vna_next field out of range: %u"), + static_cast(vna_next)); + return; + } + + pvna += vna_next; + } + + const section_size_type vn_next = verneed.get_vn_next(); + if ((p - pverneed) + vn_next >= verneed_size) + { + this->error(_("verneed vn_next field out of range: %u"), + static_cast(vn_next)); + return; + } + + p += vn_next; + } +} + +// Create a vector mapping version numbers to version strings. + +template +void +Sized_dynobj::make_version_map( + Read_symbols_data* sd, + Version_map* version_map) const +{ + if (sd->verdef == NULL && sd->verneed == NULL) + return; + + // A guess at the maximum version number we will see. If this is + // wrong we will be less efficient but still correct. + version_map->reserve(sd->verdef_info + sd->verneed_info * 10); + + this->make_verdef_map(sd, version_map); + this->make_verneed_map(sd, version_map); +} + +// Add the dynamic symbols to the symbol table. + +template +void +Sized_dynobj::do_add_symbols(Symbol_table* symtab, + Read_symbols_data* sd, + Layout*) +{ + if (sd->symbols == NULL) + { + gold_assert(sd->symbol_names == NULL); + gold_assert(sd->versym == NULL && sd->verdef == NULL + && sd->verneed == NULL); + return; + } + + const int sym_size = This::sym_size; + const size_t symcount = sd->symbols_size / sym_size; + gold_assert(sd->external_symbols_offset == 0); + if (symcount * sym_size != sd->symbols_size) + { + this->error(_("size of dynamic symbols is not multiple of symbol size")); + return; + } + + Version_map version_map; + this->make_version_map(sd, &version_map); + + // If printing symbol counts or a cross reference table or + // preparing for an incremental link, we want to track symbols. + if (parameters->options().user_set_print_symbol_counts() + || parameters->options().cref() + || parameters->incremental()) + { + this->symbols_ = new Symbols(); + this->symbols_->resize(symcount); + } + + const char* sym_names = + reinterpret_cast(sd->symbol_names->data()); + symtab->add_from_dynobj(this, sd->symbols->data(), symcount, + sym_names, sd->symbol_names_size, + (sd->versym == NULL + ? NULL + : sd->versym->data()), + sd->versym_size, + &version_map, + this->symbols_, + &this->defined_count_); + + delete sd->symbols; + sd->symbols = NULL; + delete sd->symbol_names; + sd->symbol_names = NULL; + if (sd->versym != NULL) + { + delete sd->versym; + sd->versym = NULL; + } + if (sd->verdef != NULL) + { + delete sd->verdef; + sd->verdef = NULL; + } + if (sd->verneed != NULL) + { + delete sd->verneed; + sd->verneed = NULL; + } + + // This is normally the last time we will read any data from this + // file. + this->clear_view_cache_marks(); +} + +template +Archive::Should_include +Sized_dynobj::do_should_include_member(Symbol_table*, + Layout*, + Read_symbols_data*, + std::string*) +{ + return Archive::SHOULD_INCLUDE_YES; +} + +// Iterate over global symbols, calling a visitor class V for each. + +template +void +Sized_dynobj::do_for_all_global_symbols( + Read_symbols_data* sd, + Library_base::Symbol_visitor_base* v) +{ + const char* sym_names = + reinterpret_cast(sd->symbol_names->data()); + const unsigned char* syms = + sd->symbols->data() + sd->external_symbols_offset; + const int sym_size = elfcpp::Elf_sizes::sym_size; + size_t symcount = ((sd->symbols_size - sd->external_symbols_offset) + / sym_size); + const unsigned char* p = syms; + + for (size_t i = 0; i < symcount; ++i, p += sym_size) + { + elfcpp::Sym sym(p); + if (sym.get_st_shndx() != elfcpp::SHN_UNDEF + && sym.get_st_bind() != elfcpp::STB_LOCAL) + v->visit(sym_names + sym.get_st_name()); + } +} + +// Iterate over local symbols, calling a visitor class V for each GOT offset +// associated with a local symbol. + +template +void +Sized_dynobj::do_for_all_local_got_entries( + Got_offset_list::Visitor*) const +{ +} + +// Get symbol counts. + +template +void +Sized_dynobj::do_get_global_symbol_counts( + const Symbol_table*, + size_t* defined, + size_t* used) const +{ + *defined = this->defined_count_; + size_t count = 0; + for (typename Symbols::const_iterator p = this->symbols_->begin(); + p != this->symbols_->end(); + ++p) + if (*p != NULL + && (*p)->source() == Symbol::FROM_OBJECT + && (*p)->object() == this + && (*p)->is_defined() + && (*p)->has_dynsym_index()) + ++count; + *used = count; +} + +// Given a vector of hash codes, compute the number of hash buckets to +// use. + +unsigned int +Dynobj::compute_bucket_count(const std::vector& hashcodes, + bool for_gnu_hash_table) +{ + // FIXME: Implement optional hash table optimization. + + // Array used to determine the number of hash table buckets to use + // based on the number of symbols there are. If there are fewer + // than 3 symbols we use 1 bucket, fewer than 17 symbols we use 3 + // buckets, fewer than 37 we use 17 buckets, and so forth. We never + // use more than 262147 buckets. This is straight from the old GNU + // linker. + static const unsigned int buckets[] = + { + 1, 3, 17, 37, 67, 97, 131, 197, 263, 521, 1031, 2053, 4099, 8209, + 16411, 32771, 65537, 131101, 262147 + }; + const int buckets_count = sizeof buckets / sizeof buckets[0]; + + unsigned int symcount = hashcodes.size(); + unsigned int ret = 1; + const double full_fraction + = 1.0 - parameters->options().hash_bucket_empty_fraction(); + for (int i = 0; i < buckets_count; ++i) + { + if (symcount < buckets[i] * full_fraction) + break; + ret = buckets[i]; + } + + if (for_gnu_hash_table && ret < 2) + ret = 2; + + return ret; +} + +// The standard ELF hash function. This hash function must not +// change, as the dynamic linker uses it also. + +uint32_t +Dynobj::elf_hash(const char* name) +{ + const unsigned char* nameu = reinterpret_cast(name); + uint32_t h = 0; + unsigned char c; + while ((c = *nameu++) != '\0') + { + h = (h << 4) + c; + uint32_t g = h & 0xf0000000; + if (g != 0) + { + h ^= g >> 24; + // The ELF ABI says h &= ~g, but using xor is equivalent in + // this case (since g was set from h) and may save one + // instruction. + h ^= g; + } + } + return h; +} + +// Create a standard ELF hash table, setting *PPHASH and *PHASHLEN. +// DYNSYMS is a vector with all the global dynamic symbols. +// LOCAL_DYNSYM_COUNT is the number of local symbols in the dynamic +// symbol table. + +void +Dynobj::create_elf_hash_table(const std::vector& dynsyms, + unsigned int local_dynsym_count, + unsigned char** pphash, + unsigned int* phashlen) +{ + unsigned int dynsym_count = dynsyms.size(); + + // Get the hash values for all the symbols. + std::vector dynsym_hashvals(dynsym_count); + for (unsigned int i = 0; i < dynsym_count; ++i) + dynsym_hashvals[i] = Dynobj::elf_hash(dynsyms[i]->name()); + + const unsigned int bucketcount = + Dynobj::compute_bucket_count(dynsym_hashvals, false); + + std::vector bucket(bucketcount); + std::vector chain(local_dynsym_count + dynsym_count); + + for (unsigned int i = 0; i < dynsym_count; ++i) + { + unsigned int dynsym_index = dynsyms[i]->dynsym_index(); + unsigned int bucketpos = dynsym_hashvals[i] % bucketcount; + chain[dynsym_index] = bucket[bucketpos]; + bucket[bucketpos] = dynsym_index; + } + + unsigned int hashlen = ((2 + + bucketcount + + local_dynsym_count + + dynsym_count) + * 4); + unsigned char* phash = new unsigned char[hashlen]; + + if (parameters->target().is_big_endian()) + { +#if defined(HAVE_TARGET_32_BIG) || defined(HAVE_TARGET_64_BIG) + Dynobj::sized_create_elf_hash_table(bucket, chain, phash, + hashlen); +#else + gold_unreachable(); +#endif + } + else + { +#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_64_LITTLE) + Dynobj::sized_create_elf_hash_table(bucket, chain, phash, + hashlen); +#else + gold_unreachable(); +#endif + } + + *pphash = phash; + *phashlen = hashlen; +} + +// Fill in an ELF hash table. + +template +void +Dynobj::sized_create_elf_hash_table(const std::vector& bucket, + const std::vector& chain, + unsigned char* phash, + unsigned int hashlen) +{ + unsigned char* p = phash; + + const unsigned int bucketcount = bucket.size(); + const unsigned int chaincount = chain.size(); + + elfcpp::Swap<32, big_endian>::writeval(p, bucketcount); + p += 4; + elfcpp::Swap<32, big_endian>::writeval(p, chaincount); + p += 4; + + for (unsigned int i = 0; i < bucketcount; ++i) + { + elfcpp::Swap<32, big_endian>::writeval(p, bucket[i]); + p += 4; + } + + for (unsigned int i = 0; i < chaincount; ++i) + { + elfcpp::Swap<32, big_endian>::writeval(p, chain[i]); + p += 4; + } + + gold_assert(static_cast(p - phash) == hashlen); +} + +// The hash function used for the GNU hash table. This hash function +// must not change, as the dynamic linker uses it also. + +uint32_t +Dynobj::gnu_hash(const char* name) +{ + const unsigned char* nameu = reinterpret_cast(name); + uint32_t h = 5381; + unsigned char c; + while ((c = *nameu++) != '\0') + h = (h << 5) + h + c; + return h; +} + +// Create a GNU hash table, setting *PPHASH and *PHASHLEN. GNU hash +// tables are an extension to ELF which are recognized by the GNU +// dynamic linker. They are referenced using dynamic tag DT_GNU_HASH. +// TARGET is the target. DYNSYMS is a vector with all the global +// symbols which will be going into the dynamic symbol table. +// LOCAL_DYNSYM_COUNT is the number of local symbols in the dynamic +// symbol table. + +void +Dynobj::create_gnu_hash_table(const std::vector& dynsyms, + unsigned int local_dynsym_count, + unsigned char** pphash, + unsigned int* phashlen) +{ + const unsigned int count = dynsyms.size(); + + // Sort the dynamic symbols into two vectors. Symbols which we do + // not want to put into the hash table we store into + // UNHASHED_DYNSYMS. Symbols which we do want to store we put into + // HASHED_DYNSYMS. DYNSYM_HASHVALS is parallel to HASHED_DYNSYMS, + // and records the hash codes. + + std::vector unhashed_dynsyms; + unhashed_dynsyms.reserve(count); + + std::vector hashed_dynsyms; + hashed_dynsyms.reserve(count); + + std::vector dynsym_hashvals; + dynsym_hashvals.reserve(count); + + for (unsigned int i = 0; i < count; ++i) + { + Symbol* sym = dynsyms[i]; + + if (!sym->needs_dynsym_value() + && (sym->is_undefined() + || sym->is_from_dynobj() + || sym->is_forced_local())) + unhashed_dynsyms.push_back(sym); + else + { + hashed_dynsyms.push_back(sym); + dynsym_hashvals.push_back(Dynobj::gnu_hash(sym->name())); + } + } + + // Put the unhashed symbols at the start of the global portion of + // the dynamic symbol table. + const unsigned int unhashed_count = unhashed_dynsyms.size(); + unsigned int unhashed_dynsym_index = local_dynsym_count; + for (unsigned int i = 0; i < unhashed_count; ++i) + { + unhashed_dynsyms[i]->set_dynsym_index(unhashed_dynsym_index); + ++unhashed_dynsym_index; + } + + // For the actual data generation we call out to a templatized + // function. + int size = parameters->target().get_size(); + bool big_endian = parameters->target().is_big_endian(); + if (size == 32) + { + if (big_endian) + { +#ifdef HAVE_TARGET_32_BIG + Dynobj::sized_create_gnu_hash_table<32, true>(hashed_dynsyms, + dynsym_hashvals, + unhashed_dynsym_index, + pphash, + phashlen); +#else + gold_unreachable(); +#endif + } + else + { +#ifdef HAVE_TARGET_32_LITTLE + Dynobj::sized_create_gnu_hash_table<32, false>(hashed_dynsyms, + dynsym_hashvals, + unhashed_dynsym_index, + pphash, + phashlen); +#else + gold_unreachable(); +#endif + } + } + else if (size == 64) + { + if (big_endian) + { +#ifdef HAVE_TARGET_64_BIG + Dynobj::sized_create_gnu_hash_table<64, true>(hashed_dynsyms, + dynsym_hashvals, + unhashed_dynsym_index, + pphash, + phashlen); +#else + gold_unreachable(); +#endif + } + else + { +#ifdef HAVE_TARGET_64_LITTLE + Dynobj::sized_create_gnu_hash_table<64, false>(hashed_dynsyms, + dynsym_hashvals, + unhashed_dynsym_index, + pphash, + phashlen); +#else + gold_unreachable(); +#endif + } + } + else + gold_unreachable(); +} + +// Create the actual data for a GNU hash table. This is just a copy +// of the code from the old GNU linker. + +template +void +Dynobj::sized_create_gnu_hash_table( + const std::vector& hashed_dynsyms, + const std::vector& dynsym_hashvals, + unsigned int unhashed_dynsym_count, + unsigned char** pphash, + unsigned int* phashlen) +{ + if (hashed_dynsyms.empty()) + { + // Special case for the empty hash table. + unsigned int hashlen = 5 * 4 + size / 8; + unsigned char* phash = new unsigned char[hashlen]; + // One empty bucket. + elfcpp::Swap<32, big_endian>::writeval(phash, 1); + // Symbol index above unhashed symbols. + elfcpp::Swap<32, big_endian>::writeval(phash + 4, unhashed_dynsym_count); + // One word for bitmask. + elfcpp::Swap<32, big_endian>::writeval(phash + 8, 1); + // Only bloom filter. + elfcpp::Swap<32, big_endian>::writeval(phash + 12, 0); + // No valid hashes. + elfcpp::Swap::writeval(phash + 16, 0); + // No hashes in only bucket. + elfcpp::Swap<32, big_endian>::writeval(phash + 16 + size / 8, 0); + + *phashlen = hashlen; + *pphash = phash; + + return; + } + + const unsigned int bucketcount = + Dynobj::compute_bucket_count(dynsym_hashvals, true); + + const unsigned int nsyms = hashed_dynsyms.size(); + + uint32_t maskbitslog2 = 1; + uint32_t x = nsyms >> 1; + while (x != 0) + { + ++maskbitslog2; + x >>= 1; + } + if (maskbitslog2 < 3) + maskbitslog2 = 5; + else if (((1U << (maskbitslog2 - 2)) & nsyms) != 0) + maskbitslog2 += 3; + else + maskbitslog2 += 2; + + uint32_t shift1; + if (size == 32) + shift1 = 5; + else + { + if (maskbitslog2 == 5) + maskbitslog2 = 6; + shift1 = 6; + } + uint32_t mask = (1U << shift1) - 1U; + uint32_t shift2 = maskbitslog2; + uint32_t maskbits = 1U << maskbitslog2; + uint32_t maskwords = 1U << (maskbitslog2 - shift1); + + typedef typename elfcpp::Elf_types::Elf_WXword Word; + std::vector bitmask(maskwords); + std::vector counts(bucketcount); + std::vector indx(bucketcount); + uint32_t symindx = unhashed_dynsym_count; + + // Count the number of times each hash bucket is used. + for (unsigned int i = 0; i < nsyms; ++i) + ++counts[dynsym_hashvals[i] % bucketcount]; + + unsigned int cnt = symindx; + for (unsigned int i = 0; i < bucketcount; ++i) + { + indx[i] = cnt; + cnt += counts[i]; + } + + unsigned int hashlen = (4 + bucketcount + nsyms) * 4; + hashlen += maskbits / 8; + unsigned char* phash = new unsigned char[hashlen]; + + elfcpp::Swap<32, big_endian>::writeval(phash, bucketcount); + elfcpp::Swap<32, big_endian>::writeval(phash + 4, symindx); + elfcpp::Swap<32, big_endian>::writeval(phash + 8, maskwords); + elfcpp::Swap<32, big_endian>::writeval(phash + 12, shift2); + + unsigned char* p = phash + 16 + maskbits / 8; + for (unsigned int i = 0; i < bucketcount; ++i) + { + if (counts[i] == 0) + elfcpp::Swap<32, big_endian>::writeval(p, 0); + else + elfcpp::Swap<32, big_endian>::writeval(p, indx[i]); + p += 4; + } + + for (unsigned int i = 0; i < nsyms; ++i) + { + Symbol* sym = hashed_dynsyms[i]; + uint32_t hashval = dynsym_hashvals[i]; + + unsigned int bucket = hashval % bucketcount; + unsigned int val = ((hashval >> shift1) + & ((maskbits >> shift1) - 1)); + bitmask[val] |= (static_cast(1U)) << (hashval & mask); + bitmask[val] |= (static_cast(1U)) << ((hashval >> shift2) & mask); + val = hashval & ~ 1U; + if (counts[bucket] == 1) + { + // Last element terminates the chain. + val |= 1; + } + elfcpp::Swap<32, big_endian>::writeval(p + (indx[bucket] - symindx) * 4, + val); + --counts[bucket]; + + sym->set_dynsym_index(indx[bucket]); + ++indx[bucket]; + } + + p = phash + 16; + for (unsigned int i = 0; i < maskwords; ++i) + { + elfcpp::Swap::writeval(p, bitmask[i]); + p += size / 8; + } + + *phashlen = hashlen; + *pphash = phash; +} + +// Verdef methods. + +// Write this definition to a buffer for the output section. + +template +unsigned char* +Verdef::write(const Stringpool* dynpool, bool is_last, unsigned char* pb) const +{ + const int verdef_size = elfcpp::Elf_sizes::verdef_size; + const int verdaux_size = elfcpp::Elf_sizes::verdaux_size; + + elfcpp::Verdef_write vd(pb); + vd.set_vd_version(elfcpp::VER_DEF_CURRENT); + vd.set_vd_flags((this->is_base_ ? elfcpp::VER_FLG_BASE : 0) + | (this->is_weak_ ? elfcpp::VER_FLG_WEAK : 0) + | (this->is_info_ ? elfcpp::VER_FLG_INFO : 0)); + vd.set_vd_ndx(this->index()); + vd.set_vd_cnt(1 + this->deps_.size()); + vd.set_vd_hash(Dynobj::elf_hash(this->name())); + vd.set_vd_aux(verdef_size); + vd.set_vd_next(is_last + ? 0 + : verdef_size + (1 + this->deps_.size()) * verdaux_size); + pb += verdef_size; + + elfcpp::Verdaux_write vda(pb); + vda.set_vda_name(dynpool->get_offset(this->name())); + vda.set_vda_next(this->deps_.empty() ? 0 : verdaux_size); + pb += verdaux_size; + + Deps::const_iterator p; + unsigned int i; + for (p = this->deps_.begin(), i = 0; + p != this->deps_.end(); + ++p, ++i) + { + elfcpp::Verdaux_write vda(pb); + vda.set_vda_name(dynpool->get_offset(*p)); + vda.set_vda_next(i + 1 >= this->deps_.size() ? 0 : verdaux_size); + pb += verdaux_size; + } + + return pb; +} + +// Verneed methods. + +Verneed::~Verneed() +{ + for (Need_versions::iterator p = this->need_versions_.begin(); + p != this->need_versions_.end(); + ++p) + delete *p; +} + +// Add a new version to this file reference. + +Verneed_version* +Verneed::add_name(const char* name) +{ + Verneed_version* vv = new Verneed_version(name); + this->need_versions_.push_back(vv); + return vv; +} + +// Set the version indexes starting at INDEX. + +unsigned int +Verneed::finalize(unsigned int index) +{ + for (Need_versions::iterator p = this->need_versions_.begin(); + p != this->need_versions_.end(); + ++p) + { + (*p)->set_index(index); + ++index; + } + return index; +} + +// Write this list of referenced versions to a buffer for the output +// section. + +template +unsigned char* +Verneed::write(const Stringpool* dynpool, bool is_last, + unsigned char* pb) const +{ + const int verneed_size = elfcpp::Elf_sizes::verneed_size; + const int vernaux_size = elfcpp::Elf_sizes::vernaux_size; + + elfcpp::Verneed_write vn(pb); + vn.set_vn_version(elfcpp::VER_NEED_CURRENT); + vn.set_vn_cnt(this->need_versions_.size()); + vn.set_vn_file(dynpool->get_offset(this->filename())); + vn.set_vn_aux(verneed_size); + vn.set_vn_next(is_last + ? 0 + : verneed_size + this->need_versions_.size() * vernaux_size); + pb += verneed_size; + + Need_versions::const_iterator p; + unsigned int i; + for (p = this->need_versions_.begin(), i = 0; + p != this->need_versions_.end(); + ++p, ++i) + { + elfcpp::Vernaux_write vna(pb); + vna.set_vna_hash(Dynobj::elf_hash((*p)->version())); + // FIXME: We need to sometimes set VER_FLG_WEAK here. + vna.set_vna_flags(0); + vna.set_vna_other((*p)->index()); + vna.set_vna_name(dynpool->get_offset((*p)->version())); + vna.set_vna_next(i + 1 >= this->need_versions_.size() + ? 0 + : vernaux_size); + pb += vernaux_size; + } + + return pb; +} + +// Versions methods. + +Versions::Versions(const Version_script_info& version_script, + Stringpool* dynpool) + : defs_(), needs_(), version_table_(), + is_finalized_(false), version_script_(version_script), + needs_base_version_(parameters->options().shared()) +{ + if (!this->version_script_.empty()) + { + // Parse the version script, and insert each declared version into + // defs_ and version_table_. + std::vector versions = this->version_script_.get_versions(); + + if (this->needs_base_version_ && !versions.empty()) + this->define_base_version(dynpool); + + for (size_t k = 0; k < versions.size(); ++k) + { + Stringpool::Key version_key; + const char* version = dynpool->add(versions[k].c_str(), + true, &version_key); + Verdef* const vd = new Verdef( + version, + this->version_script_.get_dependencies(version), + false, false, false, false); + this->defs_.push_back(vd); + Key key(version_key, 0); + this->version_table_.insert(std::make_pair(key, vd)); + } + } +} + +Versions::~Versions() +{ + for (Defs::iterator p = this->defs_.begin(); + p != this->defs_.end(); + ++p) + delete *p; + + for (Needs::iterator p = this->needs_.begin(); + p != this->needs_.end(); + ++p) + delete *p; +} + +// Define the base version of a shared library. The base version definition +// must be the first entry in defs_. We insert it lazily so that defs_ is +// empty if no symbol versioning is used. Then layout can just drop the +// version sections. + +void +Versions::define_base_version(Stringpool* dynpool) +{ + // If we do any versioning at all, we always need a base version, so + // define that first. Nothing explicitly declares itself as part of base, + // so it doesn't need to be in version_table_. + gold_assert(this->defs_.empty()); + const char* name = parameters->options().soname(); + if (name == NULL) + name = parameters->options().output_file_name(); + name = dynpool->add(name, false, NULL); + Verdef* vdbase = new Verdef(name, std::vector(), + true, false, false, true); + this->defs_.push_back(vdbase); + this->needs_base_version_ = false; +} + +// Return the dynamic object which a symbol refers to. + +Dynobj* +Versions::get_dynobj_for_sym(const Symbol_table* symtab, + const Symbol* sym) const +{ + if (sym->is_copied_from_dynobj()) + return symtab->get_copy_source(sym); + else + { + Object* object = sym->object(); + gold_assert(object->is_dynamic()); + return static_cast(object); + } +} + +// Record version information for a symbol going into the dynamic +// symbol table. + +void +Versions::record_version(const Symbol_table* symtab, + Stringpool* dynpool, const Symbol* sym) +{ + gold_assert(!this->is_finalized_); + gold_assert(sym->version() != NULL); + + Stringpool::Key version_key; + const char* version = dynpool->add(sym->version(), false, &version_key); + + if (!sym->is_from_dynobj() && !sym->is_copied_from_dynobj()) + { + if (parameters->options().shared()) + this->add_def(dynpool, sym, version, version_key); + } + else + { + // This is a version reference. + Dynobj* dynobj = this->get_dynobj_for_sym(symtab, sym); + this->add_need(dynpool, dynobj->soname(), version, version_key); + } +} + +// We've found a symbol SYM defined in version VERSION. + +void +Versions::add_def(Stringpool* dynpool, const Symbol* sym, const char* version, + Stringpool::Key version_key) +{ + Key k(version_key, 0); + Version_base* const vbnull = NULL; + std::pair ins = + this->version_table_.insert(std::make_pair(k, vbnull)); + + if (!ins.second) + { + // We already have an entry for this version. + Version_base* vb = ins.first->second; + + // We have now seen a symbol in this version, so it is not + // weak. + gold_assert(vb != NULL); + vb->clear_weak(); + } + else + { + // If we are creating a shared object, it is an error to + // find a definition of a symbol with a version which is not + // in the version script. + if (parameters->options().shared()) + { + gold_error(_("symbol %s has undefined version %s"), + sym->demangled_name().c_str(), version); + if (this->needs_base_version_) + this->define_base_version(dynpool); + } + else + // We only insert a base version for shared library. + gold_assert(!this->needs_base_version_); + + // When creating a regular executable, automatically define + // a new version. + Verdef* vd = new Verdef(version, std::vector(), + false, false, false, false); + this->defs_.push_back(vd); + ins.first->second = vd; + } +} + +// Add a reference to version NAME in file FILENAME. + +void +Versions::add_need(Stringpool* dynpool, const char* filename, const char* name, + Stringpool::Key name_key) +{ + Stringpool::Key filename_key; + filename = dynpool->add(filename, true, &filename_key); + + Key k(name_key, filename_key); + Version_base* const vbnull = NULL; + std::pair ins = + this->version_table_.insert(std::make_pair(k, vbnull)); + + if (!ins.second) + { + // We already have an entry for this filename/version. + return; + } + + // See whether we already have this filename. We don't expect many + // version references, so we just do a linear search. This could be + // replaced by a hash table. + Verneed* vn = NULL; + for (Needs::iterator p = this->needs_.begin(); + p != this->needs_.end(); + ++p) + { + if ((*p)->filename() == filename) + { + vn = *p; + break; + } + } + + if (vn == NULL) + { + // Create base version definition lazily for shared library. + if (this->needs_base_version_) + this->define_base_version(dynpool); + + // We have a new filename. + vn = new Verneed(filename); + this->needs_.push_back(vn); + } + + ins.first->second = vn->add_name(name); +} + +// Set the version indexes. Create a new dynamic version symbol for +// each new version definition. + +unsigned int +Versions::finalize(Symbol_table* symtab, unsigned int dynsym_index, + std::vector* syms) +{ + gold_assert(!this->is_finalized_); + + unsigned int vi = 1; + + for (Defs::iterator p = this->defs_.begin(); + p != this->defs_.end(); + ++p) + { + (*p)->set_index(vi); + ++vi; + + // Create a version symbol if necessary. + if (!(*p)->is_symbol_created()) + { + Symbol* vsym = symtab->define_as_constant((*p)->name(), + (*p)->name(), + Symbol_table::PREDEFINED, + 0, 0, + elfcpp::STT_OBJECT, + elfcpp::STB_GLOBAL, + elfcpp::STV_DEFAULT, 0, + false, false); + vsym->set_needs_dynsym_entry(); + vsym->set_dynsym_index(dynsym_index); + vsym->set_is_default(); + ++dynsym_index; + syms->push_back(vsym); + // The name is already in the dynamic pool. + } + } + + // Index 1 is used for global symbols. + if (vi == 1) + { + gold_assert(this->defs_.empty()); + vi = 2; + } + + for (Needs::iterator p = this->needs_.begin(); + p != this->needs_.end(); + ++p) + vi = (*p)->finalize(vi); + + this->is_finalized_ = true; + + return dynsym_index; +} + +// Return the version index to use for a symbol. This does two hash +// table lookups: one in DYNPOOL and one in this->version_table_. +// Another approach alternative would be store a pointer in SYM, which +// would increase the size of the symbol table. Or perhaps we could +// use a hash table from dynamic symbol pointer values to Version_base +// pointers. + +unsigned int +Versions::version_index(const Symbol_table* symtab, const Stringpool* dynpool, + const Symbol* sym) const +{ + Stringpool::Key version_key; + const char* version = dynpool->find(sym->version(), &version_key); + gold_assert(version != NULL); + + Key k; + if (!sym->is_from_dynobj() && !sym->is_copied_from_dynobj()) + { + if (!parameters->options().shared()) + return elfcpp::VER_NDX_GLOBAL; + k = Key(version_key, 0); + } + else + { + Dynobj* dynobj = this->get_dynobj_for_sym(symtab, sym); + + Stringpool::Key filename_key; + const char* filename = dynpool->find(dynobj->soname(), &filename_key); + gold_assert(filename != NULL); + + k = Key(version_key, filename_key); + } + + Version_table::const_iterator p = this->version_table_.find(k); + gold_assert(p != this->version_table_.end()); + + return p->second->index(); +} + +// Return an allocated buffer holding the contents of the symbol +// version section. + +template +void +Versions::symbol_section_contents(const Symbol_table* symtab, + const Stringpool* dynpool, + unsigned int local_symcount, + const std::vector& syms, + unsigned char** pp, + unsigned int* psize) const +{ + gold_assert(this->is_finalized_); + + unsigned int sz = (local_symcount + syms.size()) * 2; + unsigned char* pbuf = new unsigned char[sz]; + + for (unsigned int i = 0; i < local_symcount; ++i) + elfcpp::Swap<16, big_endian>::writeval(pbuf + i * 2, + elfcpp::VER_NDX_LOCAL); + + for (std::vector::const_iterator p = syms.begin(); + p != syms.end(); + ++p) + { + unsigned int version_index; + const char* version = (*p)->version(); + if (version != NULL) + version_index = this->version_index(symtab, dynpool, *p); + else + { + if ((*p)->is_defined() && !(*p)->is_from_dynobj()) + version_index = elfcpp::VER_NDX_GLOBAL; + else + version_index = elfcpp::VER_NDX_LOCAL; + } + // If the symbol was defined as foo@V1 instead of foo@@V1, add + // the hidden bit. + if ((*p)->version() != NULL && !(*p)->is_default()) + version_index |= elfcpp::VERSYM_HIDDEN; + elfcpp::Swap<16, big_endian>::writeval(pbuf + (*p)->dynsym_index() * 2, + version_index); + } + + *pp = pbuf; + *psize = sz; +} + +// Return an allocated buffer holding the contents of the version +// definition section. + +template +void +Versions::def_section_contents(const Stringpool* dynpool, + unsigned char** pp, unsigned int* psize, + unsigned int* pentries) const +{ + gold_assert(this->is_finalized_); + gold_assert(!this->defs_.empty()); + + const int verdef_size = elfcpp::Elf_sizes::verdef_size; + const int verdaux_size = elfcpp::Elf_sizes::verdaux_size; + + unsigned int sz = 0; + for (Defs::const_iterator p = this->defs_.begin(); + p != this->defs_.end(); + ++p) + { + sz += verdef_size + verdaux_size; + sz += (*p)->count_dependencies() * verdaux_size; + } + + unsigned char* pbuf = new unsigned char[sz]; + + unsigned char* pb = pbuf; + Defs::const_iterator p; + unsigned int i; + for (p = this->defs_.begin(), i = 0; + p != this->defs_.end(); + ++p, ++i) + pb = (*p)->write(dynpool, + i + 1 >= this->defs_.size(), + pb); + + gold_assert(static_cast(pb - pbuf) == sz); + + *pp = pbuf; + *psize = sz; + *pentries = this->defs_.size(); +} + +// Return an allocated buffer holding the contents of the version +// reference section. + +template +void +Versions::need_section_contents(const Stringpool* dynpool, + unsigned char** pp, unsigned int* psize, + unsigned int* pentries) const +{ + gold_assert(this->is_finalized_); + gold_assert(!this->needs_.empty()); + + const int verneed_size = elfcpp::Elf_sizes::verneed_size; + const int vernaux_size = elfcpp::Elf_sizes::vernaux_size; + + unsigned int sz = 0; + for (Needs::const_iterator p = this->needs_.begin(); + p != this->needs_.end(); + ++p) + { + sz += verneed_size; + sz += (*p)->count_versions() * vernaux_size; + } + + unsigned char* pbuf = new unsigned char[sz]; + + unsigned char* pb = pbuf; + Needs::const_iterator p; + unsigned int i; + for (p = this->needs_.begin(), i = 0; + p != this->needs_.end(); + ++p, ++i) + pb = (*p)->write(dynpool, + i + 1 >= this->needs_.size(), + pb); + + gold_assert(static_cast(pb - pbuf) == sz); + + *pp = pbuf; + *psize = sz; + *pentries = this->needs_.size(); +} + +// Instantiate the templates we need. We could use the configure +// script to restrict this to only the ones for implemented targets. + +#ifdef HAVE_TARGET_32_LITTLE +template +class Sized_dynobj<32, false>; +#endif + +#ifdef HAVE_TARGET_32_BIG +template +class Sized_dynobj<32, true>; +#endif + +#ifdef HAVE_TARGET_64_LITTLE +template +class Sized_dynobj<64, false>; +#endif + +#ifdef HAVE_TARGET_64_BIG +template +class Sized_dynobj<64, true>; +#endif + +#ifdef HAVE_TARGET_32_LITTLE +template +void +Versions::symbol_section_contents<32, false>( + const Symbol_table*, + const Stringpool*, + unsigned int, + const std::vector&, + unsigned char**, + unsigned int*) const; +#endif + +#ifdef HAVE_TARGET_32_BIG +template +void +Versions::symbol_section_contents<32, true>( + const Symbol_table*, + const Stringpool*, + unsigned int, + const std::vector&, + unsigned char**, + unsigned int*) const; +#endif + +#ifdef HAVE_TARGET_64_LITTLE +template +void +Versions::symbol_section_contents<64, false>( + const Symbol_table*, + const Stringpool*, + unsigned int, + const std::vector&, + unsigned char**, + unsigned int*) const; +#endif + +#ifdef HAVE_TARGET_64_BIG +template +void +Versions::symbol_section_contents<64, true>( + const Symbol_table*, + const Stringpool*, + unsigned int, + const std::vector&, + unsigned char**, + unsigned int*) const; +#endif + +#ifdef HAVE_TARGET_32_LITTLE +template +void +Versions::def_section_contents<32, false>( + const Stringpool*, + unsigned char**, + unsigned int*, + unsigned int*) const; +#endif + +#ifdef HAVE_TARGET_32_BIG +template +void +Versions::def_section_contents<32, true>( + const Stringpool*, + unsigned char**, + unsigned int*, + unsigned int*) const; +#endif + +#ifdef HAVE_TARGET_64_LITTLE +template +void +Versions::def_section_contents<64, false>( + const Stringpool*, + unsigned char**, + unsigned int*, + unsigned int*) const; +#endif + +#ifdef HAVE_TARGET_64_BIG +template +void +Versions::def_section_contents<64, true>( + const Stringpool*, + unsigned char**, + unsigned int*, + unsigned int*) const; +#endif + +#ifdef HAVE_TARGET_32_LITTLE +template +void +Versions::need_section_contents<32, false>( + const Stringpool*, + unsigned char**, + unsigned int*, + unsigned int*) const; +#endif + +#ifdef HAVE_TARGET_32_BIG +template +void +Versions::need_section_contents<32, true>( + const Stringpool*, + unsigned char**, + unsigned int*, + unsigned int*) const; +#endif + +#ifdef HAVE_TARGET_64_LITTLE +template +void +Versions::need_section_contents<64, false>( + const Stringpool*, + unsigned char**, + unsigned int*, + unsigned int*) const; +#endif + +#ifdef HAVE_TARGET_64_BIG +template +void +Versions::need_section_contents<64, true>( + const Stringpool*, + unsigned char**, + unsigned int*, + unsigned int*) const; +#endif + +} // End namespace gold. diff --git a/binutils-2.25/gold/dynobj.h b/binutils-2.25/gold/dynobj.h new file mode 100644 index 00000000..e027485f --- /dev/null +++ b/binutils-2.25/gold/dynobj.h @@ -0,0 +1,672 @@ +// dynobj.h -- dynamic object support for gold -*- C++ -*- + +// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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. + +#ifndef GOLD_DYNOBJ_H +#define GOLD_DYNOBJ_H + +#include + +#include "stringpool.h" +#include "object.h" + +namespace gold +{ + +class Version_script_info; + +// A dynamic object (ET_DYN). This is an abstract base class itself. +// The implementations is the template class Sized_dynobj. + +class Dynobj : public Object +{ + public: + // We keep a list of all the DT_NEEDED entries we find. + typedef std::vector Needed; + + Dynobj(const std::string& name, Input_file* input_file, off_t offset = 0); + + // Return the name to use in a DT_NEEDED entry for this object. + const char* + soname() const + { return this->soname_.c_str(); } + + // Return the list of DT_NEEDED strings. + const Needed& + needed() const + { return this->needed_; } + + // Return whether this dynamic object has any DT_NEEDED entries + // which were not seen during the link. + bool + has_unknown_needed_entries() const + { + gold_assert(this->unknown_needed_ != UNKNOWN_NEEDED_UNSET); + return this->unknown_needed_ == UNKNOWN_NEEDED_TRUE; + } + + // Set whether this dynamic object has any DT_NEEDED entries which + // were not seen during the link. + void + set_has_unknown_needed_entries(bool set) + { + gold_assert(this->unknown_needed_ == UNKNOWN_NEEDED_UNSET); + this->unknown_needed_ = set ? UNKNOWN_NEEDED_TRUE : UNKNOWN_NEEDED_FALSE; + } + + // Compute the ELF hash code for a string. + static uint32_t + elf_hash(const char*); + + // Create a standard ELF hash table, setting *PPHASH and *PHASHLEN. + // DYNSYMS is the global dynamic symbols. LOCAL_DYNSYM_COUNT is the + // number of local dynamic symbols, which is the index of the first + // dynamic gobal symbol. + static void + create_elf_hash_table(const std::vector& dynsyms, + unsigned int local_dynsym_count, + unsigned char** pphash, + unsigned int* phashlen); + + // Create a GNU hash table, setting *PPHASH and *PHASHLEN. DYNSYMS + // is the global dynamic symbols. LOCAL_DYNSYM_COUNT is the number + // of local dynamic symbols, which is the index of the first dynamic + // gobal symbol. + static void + create_gnu_hash_table(const std::vector& dynsyms, + unsigned int local_dynsym_count, + unsigned char** pphash, unsigned int* phashlen); + + protected: + // Return a pointer to this object. + virtual Dynobj* + do_dynobj() + { return this; } + + // Set the DT_SONAME string. + void + set_soname_string(const char* s) + { this->soname_.assign(s); } + + // Add an entry to the list of DT_NEEDED strings. + void + add_needed(const char* s) + { this->needed_.push_back(std::string(s)); } + + private: + // Compute the GNU hash code for a string. + static uint32_t + gnu_hash(const char*); + + // Compute the number of hash buckets to use. + static unsigned int + compute_bucket_count(const std::vector& hashcodes, + bool for_gnu_hash_table); + + // Sized version of create_elf_hash_table. + template + static void + sized_create_elf_hash_table(const std::vector& bucket, + const std::vector& chain, + unsigned char* phash, + unsigned int hashlen); + + // Sized version of create_gnu_hash_table. + template + static void + sized_create_gnu_hash_table(const std::vector& hashed_dynsyms, + const std::vector& dynsym_hashvals, + unsigned int unhashed_dynsym_count, + unsigned char** pphash, + unsigned int* phashlen); + + // Values for the has_unknown_needed_entries_ field. + enum Unknown_needed + { + UNKNOWN_NEEDED_UNSET, + UNKNOWN_NEEDED_TRUE, + UNKNOWN_NEEDED_FALSE + }; + + // The DT_SONAME name, if any. + std::string soname_; + // The list of DT_NEEDED entries. + Needed needed_; + // Whether this dynamic object has any DT_NEEDED entries not seen + // during the link. + Unknown_needed unknown_needed_; +}; + +// A dynamic object, size and endian specific version. + +template +class Sized_dynobj : public Dynobj +{ + public: + typedef typename Sized_relobj_file::Symbols Symbols; + + Sized_dynobj(const std::string& name, Input_file* input_file, off_t offset, + const typename elfcpp::Ehdr&); + + // Set up the object file based on TARGET. + void + setup(); + + // Read the symbols. + void + do_read_symbols(Read_symbols_data*); + + // Lay out the input sections. + void + do_layout(Symbol_table*, Layout*, Read_symbols_data*); + + // Add the symbols to the symbol table. + void + do_add_symbols(Symbol_table*, Read_symbols_data*, Layout*); + + Archive::Should_include + do_should_include_member(Symbol_table* symtab, Layout*, Read_symbols_data*, + std::string* why); + + // Iterate over global symbols, calling a visitor class V for each. + void + do_for_all_global_symbols(Read_symbols_data* sd, + Library_base::Symbol_visitor_base* v); + + // Iterate over local symbols, calling a visitor class V for each GOT offset + // associated with a local symbol. + void + do_for_all_local_got_entries(Got_offset_list::Visitor* v) const; + + // Get the size of a section. + uint64_t + do_section_size(unsigned int shndx) + { return this->elf_file_.section_size(shndx); } + + // Get the name of a section. + std::string + do_section_name(unsigned int shndx) + { return this->elf_file_.section_name(shndx); } + + // Return a view of the contents of a section. Set *PLEN to the + // size. + const unsigned char* + do_section_contents(unsigned int shndx, section_size_type* plen, + bool cache) + { + Location loc(this->elf_file_.section_contents(shndx)); + *plen = convert_to_section_size_type(loc.data_size); + if (*plen == 0) + { + static const unsigned char empty[1] = { '\0' }; + return empty; + } + return this->get_view(loc.file_offset, *plen, true, cache); + } + + // Return section flags. + uint64_t + do_section_flags(unsigned int shndx) + { return this->elf_file_.section_flags(shndx); } + + // Not used for dynobj. + uint64_t + do_section_entsize(unsigned int ) + { gold_unreachable(); } + + // Return section address. + uint64_t + do_section_address(unsigned int shndx) + { return this->elf_file_.section_addr(shndx); } + + // Return section type. + unsigned int + do_section_type(unsigned int shndx) + { return this->elf_file_.section_type(shndx); } + + // Return the section link field. + unsigned int + do_section_link(unsigned int shndx) + { return this->elf_file_.section_link(shndx); } + + // Return the section link field. + unsigned int + do_section_info(unsigned int shndx) + { return this->elf_file_.section_info(shndx); } + + // Return the section alignment. + uint64_t + do_section_addralign(unsigned int shndx) + { return this->elf_file_.section_addralign(shndx); } + + // Return the Xindex structure to use. + Xindex* + do_initialize_xindex(); + + // Get symbol counts. + void + do_get_global_symbol_counts(const Symbol_table*, size_t*, size_t*) const; + + // Get the global symbols. + const Symbols* + do_get_global_symbols() const + { return this->symbols_; } + + private: + // For convenience. + typedef Sized_dynobj This; + static const int shdr_size = elfcpp::Elf_sizes::shdr_size; + static const int sym_size = elfcpp::Elf_sizes::sym_size; + static const int dyn_size = elfcpp::Elf_sizes::dyn_size; + typedef elfcpp::Shdr Shdr; + typedef elfcpp::Dyn Dyn; + + // Adjust a section index if necessary. + unsigned int + adjust_shndx(unsigned int shndx) + { + if (shndx >= elfcpp::SHN_LORESERVE) + shndx += this->elf_file_.large_shndx_offset(); + return shndx; + } + + // Find the dynamic symbol table and the version sections, given the + // section headers. + void + find_dynsym_sections(const unsigned char* pshdrs, + unsigned int* pversym_shndx, + unsigned int* pverdef_shndx, + unsigned int* pverneed_shndx, + unsigned int* pdynamic_shndx); + + // Read the dynamic symbol section SHNDX. + void + read_dynsym_section(const unsigned char* pshdrs, unsigned int shndx, + elfcpp::SHT type, unsigned int link, + File_view** view, section_size_type* view_size, + unsigned int* view_info); + + // Read the dynamic tags. + void + read_dynamic(const unsigned char* pshdrs, unsigned int dynamic_shndx, + unsigned int strtab_shndx, const unsigned char* strtabu, + off_t strtab_size); + + // Mapping from version number to version name. + typedef std::vector Version_map; + + // Create the version map. + void + make_version_map(Read_symbols_data* sd, Version_map*) const; + + // Add version definitions to the version map. + void + make_verdef_map(Read_symbols_data* sd, Version_map*) const; + + // Add version references to the version map. + void + make_verneed_map(Read_symbols_data* sd, Version_map*) const; + + // Add an entry to the version map. + void + set_version_map(Version_map*, unsigned int ndx, const char* name) const; + + // General access to the ELF file. + elfcpp::Elf_file elf_file_; + // The section index of the dynamic symbol table. + unsigned int dynsym_shndx_; + // The entries in the symbol table for the symbols. We only keep + // this if we need it to print symbol information. + Symbols* symbols_; + // Number of defined symbols. + size_t defined_count_; +}; + +// A base class for Verdef and Verneed_version which just handles the +// version index which will be stored in the SHT_GNU_versym section. + +class Version_base +{ + public: + Version_base() + : index_(-1U) + { } + + virtual + ~Version_base() + { } + + // Return the version index. + unsigned int + index() const + { + gold_assert(this->index_ != -1U); + return this->index_; + } + + // Set the version index. + void + set_index(unsigned int index) + { + gold_assert(this->index_ == -1U); + this->index_ = index; + } + + // Clear the weak flag in a version definition. + virtual void + clear_weak() = 0; + + private: + Version_base(const Version_base&); + Version_base& operator=(const Version_base&); + + // The index of the version definition or reference. + unsigned int index_; +}; + +// This class handles a version being defined in the file we are +// generating. + +class Verdef : public Version_base +{ + public: + Verdef(const char* name, const std::vector& deps, + bool is_base, bool is_weak, bool is_info, bool is_symbol_created) + : name_(name), deps_(deps), is_base_(is_base), is_weak_(is_weak), + is_info_(is_info), is_symbol_created_(is_symbol_created) + { } + + // Return the version name. + const char* + name() const + { return this->name_; } + + // Return the number of dependencies. + unsigned int + count_dependencies() const + { return this->deps_.size(); } + + // Add a dependency to this version. The NAME should be + // canonicalized in the dynamic Stringpool. + void + add_dependency(const char* name) + { this->deps_.push_back(name); } + + // Return whether this definition is weak. + bool + is_weak() const + { return this->is_weak_; } + + // Clear the weak flag. + void + clear_weak() + { this->is_weak_ = false; } + + // Return whether this definition is informational. + bool + is_info() const + { return this->is_info_; } + + // Return whether a version symbol has been created for this + // definition. + bool + is_symbol_created() const + { return this->is_symbol_created_; } + + // Write contents to buffer. + template + unsigned char* + write(const Stringpool*, bool is_last, unsigned char*) const; + + private: + Verdef(const Verdef&); + Verdef& operator=(const Verdef&); + + // The type of the list of version dependencies. Each dependency + // should be canonicalized in the dynamic Stringpool. + typedef std::vector Deps; + + // The name of this version. This should be canonicalized in the + // dynamic Stringpool. + const char* name_; + // A list of other versions which this version depends upon. + Deps deps_; + // Whether this is the base version. + bool is_base_; + // Whether this version is weak. + bool is_weak_; + // Whether this version is informational. + bool is_info_; + // Whether a version symbol has been created. + bool is_symbol_created_; +}; + +// A referened version. This will be associated with a filename by +// Verneed. + +class Verneed_version : public Version_base +{ + public: + Verneed_version(const char* version) + : version_(version) + { } + + // Return the version name. + const char* + version() const + { return this->version_; } + + // Clear the weak flag. This is invalid for a reference. + void + clear_weak() + { gold_unreachable(); } + + private: + Verneed_version(const Verneed_version&); + Verneed_version& operator=(const Verneed_version&); + + const char* version_; +}; + +// Version references in a single dynamic object. + +class Verneed +{ + public: + Verneed(const char* filename) + : filename_(filename), need_versions_() + { } + + ~Verneed(); + + // Return the file name. + const char* + filename() const + { return this->filename_; } + + // Return the number of versions. + unsigned int + count_versions() const + { return this->need_versions_.size(); } + + // Add a version name. The name should be canonicalized in the + // dynamic Stringpool. If the name is already present, this does + // nothing. + Verneed_version* + add_name(const char* name); + + // Set the version indexes, starting at INDEX. Return the updated + // INDEX. + unsigned int + finalize(unsigned int index); + + // Write contents to buffer. + template + unsigned char* + write(const Stringpool*, bool is_last, unsigned char*) const; + + private: + Verneed(const Verneed&); + Verneed& operator=(const Verneed&); + + // The type of the list of version names. Each name should be + // canonicalized in the dynamic Stringpool. + typedef std::vector Need_versions; + + // The filename of the dynamic object. This should be + // canonicalized in the dynamic Stringpool. + const char* filename_; + // The list of version names. + Need_versions need_versions_; +}; + +// This class handles version definitions and references which go into +// the output file. + +class Versions +{ + public: + Versions(const Version_script_info&, Stringpool*); + + ~Versions(); + + // SYM is going into the dynamic symbol table and has a version. + // Record the appropriate version information. + void + record_version(const Symbol_table* symtab, Stringpool*, const Symbol* sym); + + // Set the version indexes. DYNSYM_INDEX is the index we should use + // for the next dynamic symbol. We add new dynamic symbols to SYMS + // and return an updated DYNSYM_INDEX. + unsigned int + finalize(Symbol_table* symtab, unsigned int dynsym_index, + std::vector* syms); + + // Return whether there are any version definitions. + bool + any_defs() const + { return !this->defs_.empty(); } + + // Return whether there are any version references. + bool + any_needs() const + { return !this->needs_.empty(); } + + // Build an allocated buffer holding the contents of the symbol + // version section (.gnu.version). + template + void + symbol_section_contents(const Symbol_table*, const Stringpool*, + unsigned int local_symcount, + const std::vector& syms, + unsigned char**, unsigned int*) const; + + // Build an allocated buffer holding the contents of the version + // definition section (.gnu.version_d). + template + void + def_section_contents(const Stringpool*, unsigned char**, + unsigned int* psize, unsigned int* pentries) const; + + // Build an allocated buffer holding the contents of the version + // reference section (.gnu.version_r). + template + void + need_section_contents(const Stringpool*, unsigned char**, + unsigned int* psize, unsigned int* pentries) const; + + const Version_script_info& + version_script() const + { return this->version_script_; } + + private: + Versions(const Versions&); + Versions& operator=(const Versions&); + + // The type of the list of version definitions. + typedef std::vector Defs; + + // The type of the list of version references. + typedef std::vector Needs; + + // Handle a symbol SYM defined with version VERSION. + void + add_def(Stringpool*, const Symbol* sym, const char* version, + Stringpool::Key); + + // Add a reference to version NAME in file FILENAME. + void + add_need(Stringpool*, const char* filename, const char* name, + Stringpool::Key); + + // Get the dynamic object to use for SYM. + Dynobj* + get_dynobj_for_sym(const Symbol_table*, const Symbol* sym) const; + + // Return the version index to use for SYM. + unsigned int + version_index(const Symbol_table*, const Stringpool*, + const Symbol* sym) const; + + // Define the base version of a shared library. + void + define_base_version(Stringpool* dynpool); + + // We keep a hash table mapping canonicalized name/version pairs to + // a version base. + typedef std::pair Key; + + struct Version_table_hash + { + size_t + operator()(const Key& k) const + { return k.first + k.second; } + }; + + struct Version_table_eq + { + bool + operator()(const Key& k1, const Key& k2) const + { return k1.first == k2.first && k1.second == k2.second; } + }; + + typedef Unordered_map Version_table; + + // The version definitions. + Defs defs_; + // The version references. + Needs needs_; + // The mapping from a canonicalized version/filename pair to a + // version index. The filename may be NULL. + Version_table version_table_; + // Whether the version indexes have been set. + bool is_finalized_; + // Contents of --version-script, if passed, or NULL. + const Version_script_info& version_script_; + // Whether we need to insert a base version. This is only used for + // shared libraries and is cleared when the base version is defined. + bool needs_base_version_; +}; + +} // End namespace gold. + +#endif // !defined(GOLD_DYNOBJ_H) diff --git a/binutils-2.25/gold/ehframe.cc b/binutils-2.25/gold/ehframe.cc new file mode 100644 index 00000000..08a9ec6b --- /dev/null +++ b/binutils-2.25/gold/ehframe.cc @@ -0,0 +1,1263 @@ +// ehframe.cc -- handle exception frame sections for gold + +// Copyright 2006, 2007, 2008, 2010, 2011, 2012 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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 +#include + +#include "elfcpp.h" +#include "dwarf.h" +#include "symtab.h" +#include "reloc.h" +#include "ehframe.h" + +namespace gold +{ + +// This file handles generation of the exception frame header that +// gcc's runtime support libraries use to find unwind information at +// runtime. This file also handles discarding duplicate exception +// frame information. + +// The exception frame header starts with four bytes: + +// 0: The version number, currently 1. + +// 1: The encoding of the pointer to the exception frames. This can +// be any DWARF unwind encoding (DW_EH_PE_*). It is normally a 4 +// byte PC relative offset (DW_EH_PE_pcrel | DW_EH_PE_sdata4). + +// 2: The encoding of the count of the number of FDE pointers in the +// lookup table. This can be any DWARF unwind encoding, and in +// particular can be DW_EH_PE_omit if the count is omitted. It is +// normally a 4 byte unsigned count (DW_EH_PE_udata4). + +// 3: The encoding of the lookup table entries. Currently gcc's +// libraries will only support DW_EH_PE_datarel | DW_EH_PE_sdata4, +// which means that the values are 4 byte offsets from the start of +// the table. + +// The exception frame header is followed by a pointer to the contents +// of the exception frame section (.eh_frame). This pointer is +// encoded as specified in the byte at offset 1 of the header (i.e., +// it is normally a 4 byte PC relative offset). + +// If there is a lookup table, this is followed by the count of the +// number of FDE pointers, encoded as specified in the byte at offset +// 2 of the header (i.e., normally a 4 byte unsigned integer). + +// This is followed by the table, which should start at an 4-byte +// aligned address in memory. Each entry in the table is 8 bytes. +// Each entry represents an FDE. The first four bytes of each entry +// are an offset to the starting PC for the FDE. The last four bytes +// of each entry are an offset to the FDE data. The offsets are from +// the start of the exception frame header information. The entries +// are in sorted order by starting PC. + +const int eh_frame_hdr_size = 4; + +// Construct the exception frame header. + +Eh_frame_hdr::Eh_frame_hdr(Output_section* eh_frame_section, + const Eh_frame* eh_frame_data) + : Output_section_data(4), + eh_frame_section_(eh_frame_section), + eh_frame_data_(eh_frame_data), + fde_offsets_(), + any_unrecognized_eh_frame_sections_(false) +{ +} + +// Set the size of the exception frame header. + +void +Eh_frame_hdr::set_final_data_size() +{ + unsigned int data_size = eh_frame_hdr_size + 4; + if (!this->any_unrecognized_eh_frame_sections_) + { + unsigned int fde_count = this->eh_frame_data_->fde_count(); + if (fde_count != 0) + data_size += 4 + 8 * fde_count; + this->fde_offsets_.reserve(fde_count); + } + this->set_data_size(data_size); +} + +// Write the data to the file. + +void +Eh_frame_hdr::do_write(Output_file* of) +{ + switch (parameters->size_and_endianness()) + { +#ifdef HAVE_TARGET_32_LITTLE + case Parameters::TARGET_32_LITTLE: + this->do_sized_write<32, false>(of); + break; +#endif +#ifdef HAVE_TARGET_32_BIG + case Parameters::TARGET_32_BIG: + this->do_sized_write<32, true>(of); + break; +#endif +#ifdef HAVE_TARGET_64_LITTLE + case Parameters::TARGET_64_LITTLE: + this->do_sized_write<64, false>(of); + break; +#endif +#ifdef HAVE_TARGET_64_BIG + case Parameters::TARGET_64_BIG: + this->do_sized_write<64, true>(of); + break; +#endif + default: + gold_unreachable(); + } +} + +// Write the data to the file with the right endianness. + +template +void +Eh_frame_hdr::do_sized_write(Output_file* of) +{ + const off_t off = this->offset(); + const off_t oview_size = this->data_size(); + unsigned char* const oview = of->get_output_view(off, oview_size); + + // Version number. + oview[0] = 1; + + // Write out a 4 byte PC relative offset to the address of the + // .eh_frame section. + oview[1] = elfcpp::DW_EH_PE_pcrel | elfcpp::DW_EH_PE_sdata4; + uint64_t eh_frame_address = this->eh_frame_section_->address(); + uint64_t eh_frame_hdr_address = this->address(); + uint64_t eh_frame_offset = (eh_frame_address - + (eh_frame_hdr_address + 4)); + elfcpp::Swap<32, big_endian>::writeval(oview + 4, eh_frame_offset); + + if (this->any_unrecognized_eh_frame_sections_ + || this->fde_offsets_.empty()) + { + // There are no FDEs, or we didn't recognize the format of the + // some of the .eh_frame sections, so we can't write out the + // sorted table. + oview[2] = elfcpp::DW_EH_PE_omit; + oview[3] = elfcpp::DW_EH_PE_omit; + + gold_assert(oview_size == 8); + } + else + { + oview[2] = elfcpp::DW_EH_PE_udata4; + oview[3] = elfcpp::DW_EH_PE_datarel | elfcpp::DW_EH_PE_sdata4; + + elfcpp::Swap<32, big_endian>::writeval(oview + 8, + this->fde_offsets_.size()); + + // We have the offsets of the FDEs in the .eh_frame section. We + // couldn't easily get the PC values before, as they depend on + // relocations which are, of course, target specific. This code + // is run after all those relocations have been applied to the + // output file. Here we read the output file again to find the + // PC values. Then we sort the list and write it out. + + Fde_addresses fde_addresses(this->fde_offsets_.size()); + this->get_fde_addresses(of, &this->fde_offsets_, + &fde_addresses); + + std::sort(fde_addresses.begin(), fde_addresses.end(), + Fde_address_compare()); + + typename elfcpp::Elf_types::Elf_Addr output_address; + output_address = this->address(); + + unsigned char* pfde = oview + 12; + for (typename Fde_addresses::iterator p = fde_addresses.begin(); + p != fde_addresses.end(); + ++p) + { + elfcpp::Swap<32, big_endian>::writeval(pfde, + p->first - output_address); + elfcpp::Swap<32, big_endian>::writeval(pfde + 4, + p->second - output_address); + pfde += 8; + } + + gold_assert(pfde - oview == oview_size); + } + + of->write_output_view(off, oview_size, oview); +} + +// Given the offset FDE_OFFSET of an FDE in the .eh_frame section, and +// the contents of the .eh_frame section EH_FRAME_CONTENTS, where the +// FDE's encoding is FDE_ENCODING, return the output address of the +// FDE's PC. + +template +typename elfcpp::Elf_types::Elf_Addr +Eh_frame_hdr::get_fde_pc( + typename elfcpp::Elf_types::Elf_Addr eh_frame_address, + const unsigned char* eh_frame_contents, + section_offset_type fde_offset, + unsigned char fde_encoding) +{ + // The FDE starts with a 4 byte length and a 4 byte offset to the + // CIE. The PC follows. + const unsigned char* p = eh_frame_contents + fde_offset + 8; + + typename elfcpp::Elf_types::Elf_Addr pc; + bool is_signed = (fde_encoding & elfcpp::DW_EH_PE_signed) != 0; + int pc_size = fde_encoding & 7; + if (pc_size == elfcpp::DW_EH_PE_absptr) + { + if (size == 32) + pc_size = elfcpp::DW_EH_PE_udata4; + else if (size == 64) + pc_size = elfcpp::DW_EH_PE_udata8; + else + gold_unreachable(); + } + + switch (pc_size) + { + case elfcpp::DW_EH_PE_udata2: + pc = elfcpp::Swap<16, big_endian>::readval(p); + if (is_signed) + pc = (pc ^ 0x8000) - 0x8000; + break; + + case elfcpp::DW_EH_PE_udata4: + pc = elfcpp::Swap<32, big_endian>::readval(p); + if (size > 32 && is_signed) + pc = (pc ^ 0x80000000) - 0x80000000; + break; + + case elfcpp::DW_EH_PE_udata8: + gold_assert(size == 64); + pc = elfcpp::Swap_unaligned<64, big_endian>::readval(p); + break; + + default: + // All other cases were rejected in Eh_frame::read_cie. + gold_unreachable(); + } + + switch (fde_encoding & 0x70) + { + case 0: + break; + + case elfcpp::DW_EH_PE_pcrel: + pc += eh_frame_address + fde_offset + 8; + break; + + case elfcpp::DW_EH_PE_datarel: + pc += parameters->target().ehframe_datarel_base(); + break; + + default: + // If other cases arise, then we have to handle them, or we have + // to reject them by returning false in Eh_frame::read_cie. + gold_unreachable(); + } + + gold_assert((fde_encoding & elfcpp::DW_EH_PE_indirect) == 0); + + return pc; +} + +// Given an array of FDE offsets in the .eh_frame section, return an +// array of offsets from the exception frame header to the FDE's +// output PC and to the output address of the FDE itself. We get the +// FDE's PC by actually looking in the .eh_frame section we just wrote +// to the output file. + +template +void +Eh_frame_hdr::get_fde_addresses(Output_file* of, + const Fde_offsets* fde_offsets, + Fde_addresses* fde_addresses) +{ + typename elfcpp::Elf_types::Elf_Addr eh_frame_address; + eh_frame_address = this->eh_frame_section_->address(); + off_t eh_frame_offset = this->eh_frame_section_->offset(); + off_t eh_frame_size = this->eh_frame_section_->data_size(); + const unsigned char* eh_frame_contents = of->get_input_view(eh_frame_offset, + eh_frame_size); + + for (Fde_offsets::const_iterator p = fde_offsets->begin(); + p != fde_offsets->end(); + ++p) + { + typename elfcpp::Elf_types::Elf_Addr fde_pc; + fde_pc = this->get_fde_pc(eh_frame_address, + eh_frame_contents, + p->first, p->second); + fde_addresses->push_back(fde_pc, eh_frame_address + p->first); + } + + of->free_input_view(eh_frame_offset, eh_frame_size, eh_frame_contents); +} + +// Class Fde. + +// Write the FDE to OVIEW starting at OFFSET. CIE_OFFSET is the +// offset of the CIE in OVIEW. FDE_ENCODING is the encoding, from the +// CIE. ADDRALIGN is the required alignment. ADDRESS is the virtual +// address of OVIEW. Record the FDE pc for EH_FRAME_HDR. Return the +// new offset. + +template +section_offset_type +Fde::write(unsigned char* oview, section_offset_type offset, + uint64_t address, unsigned int addralign, + section_offset_type cie_offset, unsigned char fde_encoding, + Eh_frame_hdr* eh_frame_hdr) +{ + gold_assert((offset & (addralign - 1)) == 0); + + size_t length = this->contents_.length(); + + // We add 8 when getting the aligned length to account for the + // length word and the CIE offset. + size_t aligned_full_length = align_address(length + 8, addralign); + + // Write the length of the FDE as a 32-bit word. The length word + // does not include the four bytes of the length word itself, but it + // does include the offset to the CIE. + elfcpp::Swap<32, big_endian>::writeval(oview + offset, + aligned_full_length - 4); + + // Write the offset to the CIE as a 32-bit word. This is the + // difference between the address of the offset word itself and the + // CIE address. + elfcpp::Swap<32, big_endian>::writeval(oview + offset + 4, + offset + 4 - cie_offset); + + // Copy the rest of the FDE. Note that this is run before + // relocation processing is done on this section, so the relocations + // will later be applied to the FDE data. + memcpy(oview + offset + 8, this->contents_.data(), length); + + // If this FDE is associated with a PLT, fill in the PLT's address + // and size. + if (this->object_ == NULL) + { + gold_assert(memcmp(oview + offset + 8, "\0\0\0\0\0\0\0\0", 8) == 0); + uint64_t paddress; + off_t psize; + parameters->target().plt_fde_location(this->u_.from_linker.plt, + oview + offset + 8, + &paddress, &psize); + uint64_t poffset = paddress - (address + offset + 8); + int32_t spoffset = static_cast(poffset); + uint32_t upsize = static_cast(psize); + if (static_cast(static_cast(spoffset)) != poffset + || static_cast(upsize) != psize) + gold_warning(_("overflow in PLT unwind data; " + "unwinding through PLT may fail")); + elfcpp::Swap<32, big_endian>::writeval(oview + offset + 8, spoffset); + elfcpp::Swap<32, big_endian>::writeval(oview + offset + 12, upsize); + } + + if (aligned_full_length > length + 8) + memset(oview + offset + length + 8, 0, aligned_full_length - (length + 8)); + + // Tell the exception frame header about this FDE. + if (eh_frame_hdr != NULL) + eh_frame_hdr->record_fde(offset, fde_encoding); + + return offset + aligned_full_length; +} + +// Class Cie. + +// Destructor. + +Cie::~Cie() +{ + for (std::vector::iterator p = this->fdes_.begin(); + p != this->fdes_.end(); + ++p) + delete *p; +} + +// Set the output offset of a CIE. Return the new output offset. + +section_offset_type +Cie::set_output_offset(section_offset_type output_offset, + unsigned int addralign, + Merge_map* merge_map) +{ + size_t length = this->contents_.length(); + + // Add 4 for length and 4 for zero CIE identifier tag. + length += 8; + + if (this->object_ != NULL) + { + // Add a mapping so that relocations are applied correctly. + merge_map->add_mapping(this->object_, this->shndx_, this->input_offset_, + length, output_offset); + } + + length = align_address(length, addralign); + + for (std::vector::const_iterator p = this->fdes_.begin(); + p != this->fdes_.end(); + ++p) + { + (*p)->add_mapping(output_offset + length, merge_map); + + size_t fde_length = (*p)->length(); + fde_length = align_address(fde_length, addralign); + length += fde_length; + } + + return output_offset + length; +} + +// Write the CIE to OVIEW starting at OFFSET. Round up the bytes to +// ADDRALIGN. ADDRESS is the virtual address of OVIEW. +// EH_FRAME_HDR is the exception frame header for FDE recording. +// POST_FDES stashes FDEs created after mappings were done, for later +// writing. Return the new offset. + +template +section_offset_type +Cie::write(unsigned char* oview, section_offset_type offset, + uint64_t address, unsigned int addralign, + Eh_frame_hdr* eh_frame_hdr, Post_fdes* post_fdes) +{ + gold_assert((offset & (addralign - 1)) == 0); + + section_offset_type cie_offset = offset; + + size_t length = this->contents_.length(); + + // We add 8 when getting the aligned length to account for the + // length word and the CIE tag. + size_t aligned_full_length = align_address(length + 8, addralign); + + // Write the length of the CIE as a 32-bit word. The length word + // does not include the four bytes of the length word itself. + elfcpp::Swap<32, big_endian>::writeval(oview + offset, + aligned_full_length - 4); + + // Write the tag which marks this as a CIE: a 32-bit zero. + elfcpp::Swap<32, big_endian>::writeval(oview + offset + 4, 0); + + // Write out the CIE data. + memcpy(oview + offset + 8, this->contents_.data(), length); + + if (aligned_full_length > length + 8) + memset(oview + offset + length + 8, 0, aligned_full_length - (length + 8)); + + offset += aligned_full_length; + + // Write out the associated FDEs. + unsigned char fde_encoding = this->fde_encoding_; + for (std::vector::const_iterator p = this->fdes_.begin(); + p != this->fdes_.end(); + ++p) + { + if ((*p)->post_map()) + post_fdes->push_back(Post_fde(*p, cie_offset, fde_encoding)); + else + offset = (*p)->write(oview, offset, address, + addralign, cie_offset, + fde_encoding, eh_frame_hdr); + } + + return offset; +} + +// We track all the CIEs we see, and merge them when possible. This +// works because each FDE holds an offset to the relevant CIE: we +// rewrite the FDEs to point to the merged CIE. This is worthwhile +// because in a typical C++ program many FDEs in many different object +// files will use the same CIE. + +// An equality operator for Cie. + +bool +operator==(const Cie& cie1, const Cie& cie2) +{ + return (cie1.personality_name_ == cie2.personality_name_ + && cie1.contents_ == cie2.contents_); +} + +// A less-than operator for Cie. + +bool +operator<(const Cie& cie1, const Cie& cie2) +{ + if (cie1.personality_name_ != cie2.personality_name_) + return cie1.personality_name_ < cie2.personality_name_; + return cie1.contents_ < cie2.contents_; +} + +// Class Eh_frame. + +Eh_frame::Eh_frame() + : Output_section_data(Output_data::default_alignment()), + eh_frame_hdr_(NULL), + cie_offsets_(), + unmergeable_cie_offsets_(), + merge_map_(), + mappings_are_done_(false), + final_data_size_(0) +{ +} + +// Skip an LEB128, updating *PP to point to the next character. +// Return false if we ran off the end of the string. + +bool +Eh_frame::skip_leb128(const unsigned char** pp, const unsigned char* pend) +{ + const unsigned char* p; + for (p = *pp; p < pend; ++p) + { + if ((*p & 0x80) == 0) + { + *pp = p + 1; + return true; + } + } + return false; +} + +// Add input section SHNDX in OBJECT to an exception frame section. +// SYMBOLS is the contents of the symbol table section (size +// SYMBOLS_SIZE), SYMBOL_NAMES is the symbol names section (size +// SYMBOL_NAMES_SIZE). RELOC_SHNDX is the index of a relocation +// section applying to SHNDX, or 0 if none, or -1U if more than one. +// RELOC_TYPE is the type of the reloc section if there is one, either +// SHT_REL or SHT_RELA. We try to parse the input exception frame +// data into our data structures. If we can't do it, we return false +// to mean that the section should be handled as a normal input +// section. + +template +bool +Eh_frame::add_ehframe_input_section( + Sized_relobj_file* object, + const unsigned char* symbols, + section_size_type symbols_size, + const unsigned char* symbol_names, + section_size_type symbol_names_size, + unsigned int shndx, + unsigned int reloc_shndx, + unsigned int reloc_type) +{ + // Get the section contents. + section_size_type contents_len; + const unsigned char* pcontents = object->section_contents(shndx, + &contents_len, + false); + if (contents_len == 0) + return false; + + // If this is the marker section for the end of the data, then + // return false to force it to be handled as an ordinary input + // section. If we don't do this, we won't correctly handle the case + // of unrecognized .eh_frame sections. + if (contents_len == 4 + && elfcpp::Swap<32, big_endian>::readval(pcontents) == 0) + return false; + + New_cies new_cies; + if (!this->do_add_ehframe_input_section(object, symbols, symbols_size, + symbol_names, symbol_names_size, + shndx, reloc_shndx, + reloc_type, pcontents, + contents_len, &new_cies)) + { + if (this->eh_frame_hdr_ != NULL) + this->eh_frame_hdr_->found_unrecognized_eh_frame_section(); + + for (New_cies::iterator p = new_cies.begin(); + p != new_cies.end(); + ++p) + delete p->first; + + return false; + } + + // Now that we know we are using this section, record any new CIEs + // that we found. + for (New_cies::const_iterator p = new_cies.begin(); + p != new_cies.end(); + ++p) + { + if (p->second) + this->cie_offsets_.insert(p->first); + else + this->unmergeable_cie_offsets_.push_back(p->first); + } + + return true; +} + +// The bulk of the implementation of add_ehframe_input_section. + +template +bool +Eh_frame::do_add_ehframe_input_section( + Sized_relobj_file* object, + const unsigned char* symbols, + section_size_type symbols_size, + const unsigned char* symbol_names, + section_size_type symbol_names_size, + unsigned int shndx, + unsigned int reloc_shndx, + unsigned int reloc_type, + const unsigned char* pcontents, + section_size_type contents_len, + New_cies* new_cies) +{ + Track_relocs relocs; + + const unsigned char* p = pcontents; + const unsigned char* pend = p + contents_len; + + // Get the contents of the reloc section if any. + if (!relocs.initialize(object, reloc_shndx, reloc_type)) + return false; + + // Keep track of which CIEs are at which offsets. + Offsets_to_cie cies; + + while (p < pend) + { + if (pend - p < 4) + return false; + + // There shouldn't be any relocations here. + if (relocs.advance(p + 4 - pcontents) > 0) + return false; + + unsigned int len = elfcpp::Swap<32, big_endian>::readval(p); + p += 4; + if (len == 0) + { + // We should only find a zero-length entry at the end of the + // section. + if (p < pend) + return false; + break; + } + // We don't support a 64-bit .eh_frame. + if (len == 0xffffffff) + return false; + if (static_cast(pend - p) < len) + return false; + + const unsigned char* const pentend = p + len; + + if (pend - p < 4) + return false; + if (relocs.advance(p + 4 - pcontents) > 0) + return false; + + unsigned int id = elfcpp::Swap<32, big_endian>::readval(p); + p += 4; + + if (id == 0) + { + // CIE. + if (!this->read_cie(object, shndx, symbols, symbols_size, + symbol_names, symbol_names_size, + pcontents, p, pentend, &relocs, &cies, + new_cies)) + return false; + } + else + { + // FDE. + if (!this->read_fde(object, shndx, symbols, symbols_size, + pcontents, id, p, pentend, &relocs, &cies)) + return false; + } + + p = pentend; + } + + return true; +} + +// Read a CIE. Return false if we can't parse the information. + +template +bool +Eh_frame::read_cie(Sized_relobj_file* object, + unsigned int shndx, + const unsigned char* symbols, + section_size_type symbols_size, + const unsigned char* symbol_names, + section_size_type symbol_names_size, + const unsigned char* pcontents, + const unsigned char* pcie, + const unsigned char* pcieend, + Track_relocs* relocs, + Offsets_to_cie* cies, + New_cies* new_cies) +{ + bool mergeable = true; + + // We need to find the personality routine if there is one, since we + // can only merge CIEs which use the same routine. We also need to + // find the FDE encoding if there is one, so that we can read the PC + // from the FDE. + + const unsigned char* p = pcie; + + if (pcieend - p < 1) + return false; + unsigned char version = *p++; + if (version != 1 && version != 3) + return false; + + const unsigned char* paug = p; + const void* paugendv = memchr(p, '\0', pcieend - p); + const unsigned char* paugend = static_cast(paugendv); + if (paugend == NULL) + return false; + p = paugend + 1; + + if (paug[0] == 'e' && paug[1] == 'h') + { + // This is a CIE from gcc before version 3.0. We can't merge + // these. We can still read the FDEs. + mergeable = false; + paug += 2; + if (*paug != '\0') + return false; + if (pcieend - p < size / 8) + return false; + p += size / 8; + } + + // Skip the code alignment. + if (!skip_leb128(&p, pcieend)) + return false; + + // Skip the data alignment. + if (!skip_leb128(&p, pcieend)) + return false; + + // Skip the return column. + if (version == 1) + { + if (pcieend - p < 1) + return false; + ++p; + } + else + { + if (!skip_leb128(&p, pcieend)) + return false; + } + + if (*paug == 'z') + { + ++paug; + // Skip the augmentation size. + if (!skip_leb128(&p, pcieend)) + return false; + } + + unsigned char fde_encoding = elfcpp::DW_EH_PE_absptr; + int per_offset = -1; + while (*paug != '\0') + { + switch (*paug) + { + case 'L': // LSDA encoding. + if (pcieend - p < 1) + return false; + ++p; + break; + + case 'R': // FDE encoding. + if (pcieend - p < 1) + return false; + fde_encoding = *p; + switch (fde_encoding & 7) + { + case elfcpp::DW_EH_PE_absptr: + case elfcpp::DW_EH_PE_udata2: + case elfcpp::DW_EH_PE_udata4: + case elfcpp::DW_EH_PE_udata8: + break; + default: + // We don't expect to see any other cases here, and + // we're not prepared to handle them. + return false; + } + ++p; + break; + + case 'S': + break; + + case 'P': + // Personality encoding. + { + if (pcieend - p < 1) + return false; + unsigned char per_encoding = *p; + ++p; + + if ((per_encoding & 0x60) == 0x60) + return false; + unsigned int per_width; + switch (per_encoding & 7) + { + case elfcpp::DW_EH_PE_udata2: + per_width = 2; + break; + case elfcpp::DW_EH_PE_udata4: + per_width = 4; + break; + case elfcpp::DW_EH_PE_udata8: + per_width = 8; + break; + case elfcpp::DW_EH_PE_absptr: + per_width = size / 8; + break; + default: + return false; + } + + if ((per_encoding & 0xf0) == elfcpp::DW_EH_PE_aligned) + { + unsigned int len = p - pcie; + len += per_width - 1; + len &= ~ (per_width - 1); + if (static_cast(pcieend - p) < len) + return false; + p += len; + } + + per_offset = p - pcontents; + + if (static_cast(pcieend - p) < per_width) + return false; + p += per_width; + } + break; + + default: + return false; + } + + ++paug; + } + + const char* personality_name = ""; + if (per_offset != -1) + { + if (relocs->advance(per_offset) > 0) + return false; + if (relocs->next_offset() != per_offset) + return false; + + unsigned int personality_symndx = relocs->next_symndx(); + if (personality_symndx == -1U) + return false; + + if (personality_symndx < object->local_symbol_count()) + { + // We can only merge this CIE if the personality routine is + // a global symbol. We can still read the FDEs. + mergeable = false; + } + else + { + const int sym_size = elfcpp::Elf_sizes::sym_size; + if (personality_symndx >= symbols_size / sym_size) + return false; + elfcpp::Sym sym(symbols + + (personality_symndx * sym_size)); + unsigned int name_offset = sym.get_st_name(); + if (name_offset >= symbol_names_size) + return false; + personality_name = (reinterpret_cast(symbol_names) + + name_offset); + } + + int r = relocs->advance(per_offset + 1); + gold_assert(r == 1); + } + + if (relocs->advance(pcieend - pcontents) > 0) + return false; + + Cie cie(object, shndx, (pcie - 8) - pcontents, fde_encoding, + personality_name, pcie, pcieend - pcie); + Cie* cie_pointer = NULL; + if (mergeable) + { + Cie_offsets::iterator find_cie = this->cie_offsets_.find(&cie); + if (find_cie != this->cie_offsets_.end()) + cie_pointer = *find_cie; + else + { + // See if we already saw this CIE in this object file. + for (New_cies::const_iterator pc = new_cies->begin(); + pc != new_cies->end(); + ++pc) + { + if (*(pc->first) == cie) + { + cie_pointer = pc->first; + break; + } + } + } + } + + if (cie_pointer == NULL) + { + cie_pointer = new Cie(cie); + new_cies->push_back(std::make_pair(cie_pointer, mergeable)); + } + else + { + // We are deleting this CIE. Record that in our mapping from + // input sections to the output section. At this point we don't + // know for sure that we are doing a special mapping for this + // input section, but that's OK--if we don't do a special + // mapping, nobody will ever ask for the mapping we add here. + this->merge_map_.add_mapping(object, shndx, (pcie - 8) - pcontents, + pcieend - (pcie - 8), -1); + } + + // Record this CIE plus the offset in the input section. + cies->insert(std::make_pair(pcie - pcontents, cie_pointer)); + + return true; +} + +// Read an FDE. Return false if we can't parse the information. + +template +bool +Eh_frame::read_fde(Sized_relobj_file* object, + unsigned int shndx, + const unsigned char* symbols, + section_size_type symbols_size, + const unsigned char* pcontents, + unsigned int offset, + const unsigned char* pfde, + const unsigned char* pfdeend, + Track_relocs* relocs, + Offsets_to_cie* cies) +{ + // OFFSET is the distance between the 4 bytes before PFDE to the + // start of the CIE. The offset we recorded for the CIE is 8 bytes + // after the start of the CIE--after the length and the zero tag. + unsigned int cie_offset = (pfde - 4 - pcontents) - offset + 8; + Offsets_to_cie::const_iterator pcie = cies->find(cie_offset); + if (pcie == cies->end()) + return false; + Cie* cie = pcie->second; + + // The FDE should start with a reloc to the start of the code which + // it describes. + if (relocs->advance(pfde - pcontents) > 0) + return false; + + if (relocs->next_offset() != pfde - pcontents) + return false; + + unsigned int symndx = relocs->next_symndx(); + if (symndx == -1U) + return false; + + // There can be another reloc in the FDE, if the CIE specifies an + // LSDA (language specific data area). We currently don't care. We + // will care later if we want to optimize the LSDA from an absolute + // pointer to a PC relative offset when generating a shared library. + relocs->advance(pfdeend - pcontents); + + unsigned int fde_shndx; + const int sym_size = elfcpp::Elf_sizes::sym_size; + if (symndx >= symbols_size / sym_size) + return false; + elfcpp::Sym sym(symbols + symndx * sym_size); + bool is_ordinary; + fde_shndx = object->adjust_sym_shndx(symndx, sym.get_st_shndx(), + &is_ordinary); + + if (is_ordinary + && fde_shndx != elfcpp::SHN_UNDEF + && fde_shndx < object->shnum() + && !object->is_section_included(fde_shndx)) + { + // This FDE applies to a section which we are discarding. We + // can discard this FDE. + this->merge_map_.add_mapping(object, shndx, (pfde - 8) - pcontents, + pfdeend - (pfde - 8), -1); + return true; + } + + cie->add_fde(new Fde(object, shndx, (pfde - 8) - pcontents, + pfde, pfdeend - pfde)); + + return true; +} + +// Add unwind information for a PLT. + +void +Eh_frame::add_ehframe_for_plt(Output_data* plt, const unsigned char* cie_data, + size_t cie_length, const unsigned char* fde_data, + size_t fde_length) +{ + Cie cie(NULL, 0, 0, elfcpp::DW_EH_PE_pcrel | elfcpp::DW_EH_PE_sdata4, "", + cie_data, cie_length); + Cie_offsets::iterator find_cie = this->cie_offsets_.find(&cie); + Cie* pcie; + if (find_cie != this->cie_offsets_.end()) + pcie = *find_cie; + else + { + gold_assert(!this->mappings_are_done_); + pcie = new Cie(cie); + this->cie_offsets_.insert(pcie); + } + + Fde* fde = new Fde(plt, fde_data, fde_length, this->mappings_are_done_); + pcie->add_fde(fde); + + if (this->mappings_are_done_) + this->final_data_size_ += align_address(fde_length + 8, this->addralign()); +} + +// Return the number of FDEs. + +unsigned int +Eh_frame::fde_count() const +{ + unsigned int ret = 0; + for (Unmergeable_cie_offsets::const_iterator p = + this->unmergeable_cie_offsets_.begin(); + p != this->unmergeable_cie_offsets_.end(); + ++p) + ret += (*p)->fde_count(); + for (Cie_offsets::const_iterator p = this->cie_offsets_.begin(); + p != this->cie_offsets_.end(); + ++p) + ret += (*p)->fde_count(); + return ret; +} + +// Set the final data size. + +void +Eh_frame::set_final_data_size() +{ + // We can be called more than once if Layout::set_segment_offsets + // finds a better mapping. We don't want to add all the mappings + // again. + if (this->mappings_are_done_) + { + this->set_data_size(this->final_data_size_); + return; + } + + section_offset_type output_offset = 0; + + for (Unmergeable_cie_offsets::iterator p = + this->unmergeable_cie_offsets_.begin(); + p != this->unmergeable_cie_offsets_.end(); + ++p) + output_offset = (*p)->set_output_offset(output_offset, + this->addralign(), + &this->merge_map_); + + for (Cie_offsets::iterator p = this->cie_offsets_.begin(); + p != this->cie_offsets_.end(); + ++p) + output_offset = (*p)->set_output_offset(output_offset, + this->addralign(), + &this->merge_map_); + + this->mappings_are_done_ = true; + this->final_data_size_ = output_offset; + + gold_assert((output_offset & (this->addralign() - 1)) == 0); + this->set_data_size(output_offset); +} + +// Return an output offset for an input offset. + +bool +Eh_frame::do_output_offset(const Relobj* object, unsigned int shndx, + section_offset_type offset, + section_offset_type* poutput) const +{ + return this->merge_map_.get_output_offset(object, shndx, offset, poutput); +} + +// Return whether this is the merge section for an input section. + +bool +Eh_frame::do_is_merge_section_for(const Relobj* object, + unsigned int shndx) const +{ + return this->merge_map_.is_merge_section_for(object, shndx); +} + +// Write the data to the output file. + +void +Eh_frame::do_write(Output_file* of) +{ + const off_t offset = this->offset(); + const off_t oview_size = this->data_size(); + unsigned char* const oview = of->get_output_view(offset, oview_size); + + switch (parameters->size_and_endianness()) + { +#ifdef HAVE_TARGET_32_LITTLE + case Parameters::TARGET_32_LITTLE: + this->do_sized_write<32, false>(oview); + break; +#endif +#ifdef HAVE_TARGET_32_BIG + case Parameters::TARGET_32_BIG: + this->do_sized_write<32, true>(oview); + break; +#endif +#ifdef HAVE_TARGET_64_LITTLE + case Parameters::TARGET_64_LITTLE: + this->do_sized_write<64, false>(oview); + break; +#endif +#ifdef HAVE_TARGET_64_BIG + case Parameters::TARGET_64_BIG: + this->do_sized_write<64, true>(oview); + break; +#endif + default: + gold_unreachable(); + } + + of->write_output_view(offset, oview_size, oview); +} + +// Write the data to the output file--template version. + +template +void +Eh_frame::do_sized_write(unsigned char* oview) +{ + uint64_t address = this->address(); + unsigned int addralign = this->addralign(); + section_offset_type o = 0; + Post_fdes post_fdes; + for (Unmergeable_cie_offsets::iterator p = + this->unmergeable_cie_offsets_.begin(); + p != this->unmergeable_cie_offsets_.end(); + ++p) + o = (*p)->write(oview, o, address, addralign, + this->eh_frame_hdr_, &post_fdes); + for (Cie_offsets::iterator p = this->cie_offsets_.begin(); + p != this->cie_offsets_.end(); + ++p) + o = (*p)->write(oview, o, address, addralign, + this->eh_frame_hdr_, &post_fdes); + for (Post_fdes::iterator p = post_fdes.begin(); + p != post_fdes.end(); + ++p) + o = (*p).fde->write(oview, o, address, addralign, + (*p).cie_offset, + (*p).fde_encoding, + this->eh_frame_hdr_); +} + +#ifdef HAVE_TARGET_32_LITTLE +template +bool +Eh_frame::add_ehframe_input_section<32, false>( + Sized_relobj_file<32, false>* object, + const unsigned char* symbols, + section_size_type symbols_size, + const unsigned char* symbol_names, + section_size_type symbol_names_size, + unsigned int shndx, + unsigned int reloc_shndx, + unsigned int reloc_type); +#endif + +#ifdef HAVE_TARGET_32_BIG +template +bool +Eh_frame::add_ehframe_input_section<32, true>( + Sized_relobj_file<32, true>* object, + const unsigned char* symbols, + section_size_type symbols_size, + const unsigned char* symbol_names, + section_size_type symbol_names_size, + unsigned int shndx, + unsigned int reloc_shndx, + unsigned int reloc_type); +#endif + +#ifdef HAVE_TARGET_64_LITTLE +template +bool +Eh_frame::add_ehframe_input_section<64, false>( + Sized_relobj_file<64, false>* object, + const unsigned char* symbols, + section_size_type symbols_size, + const unsigned char* symbol_names, + section_size_type symbol_names_size, + unsigned int shndx, + unsigned int reloc_shndx, + unsigned int reloc_type); +#endif + +#ifdef HAVE_TARGET_64_BIG +template +bool +Eh_frame::add_ehframe_input_section<64, true>( + Sized_relobj_file<64, true>* object, + const unsigned char* symbols, + section_size_type symbols_size, + const unsigned char* symbol_names, + section_size_type symbol_names_size, + unsigned int shndx, + unsigned int reloc_shndx, + unsigned int reloc_type); +#endif + +} // End namespace gold. diff --git a/binutils-2.25/gold/ehframe.h b/binutils-2.25/gold/ehframe.h new file mode 100644 index 00000000..8aab8b81 --- /dev/null +++ b/binutils-2.25/gold/ehframe.h @@ -0,0 +1,517 @@ +// ehframe.h -- handle exception frame sections for gold -*- C++ -*- + +// Copyright 2006, 2007, 2008, 2010, 2011 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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. + +#ifndef GOLD_EHFRAME_H +#define GOLD_EHFRAME_H + +#include +#include +#include + +#include "output.h" +#include "merge.h" + +namespace gold +{ + +template +class Track_relocs; + +class Eh_frame; + +// This class manages the .eh_frame_hdr section, which holds the data +// for the PT_GNU_EH_FRAME segment. gcc's unwind support code uses +// the PT_GNU_EH_FRAME segment to find the list of FDEs. This saves +// the time required to register the exception handlers at startup +// time and when a shared object is loaded, and the time required to +// deregister the exception handlers when a shared object is unloaded. + +class Eh_frame_hdr : public Output_section_data +{ + public: + Eh_frame_hdr(Output_section* eh_frame_section, const Eh_frame*); + + // Record that we found an unrecognized .eh_frame section. + void + found_unrecognized_eh_frame_section() + { this->any_unrecognized_eh_frame_sections_ = true; } + + // Record an FDE. + void + record_fde(section_offset_type fde_offset, unsigned char fde_encoding) + { + if (!this->any_unrecognized_eh_frame_sections_) + this->fde_offsets_.push_back(std::make_pair(fde_offset, fde_encoding)); + } + + protected: + // Set the final data size. + void + set_final_data_size(); + + // Write the data to the file. + void + do_write(Output_file*); + + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _("** eh_frame_hdr")); } + + private: + // Write the data to the file with the right endianness. + template + void + do_sized_write(Output_file*); + + // The data we record for one FDE: the offset of the FDE within the + // .eh_frame section, and the FDE encoding. + typedef std::pair Fde_offset; + + // The list of information we record for an FDE. + typedef std::vector Fde_offsets; + + // When writing out the header, we convert the FDE offsets into FDE + // addresses. This is a list of pairs of the offset from the header + // to the FDE PC and to the FDE itself. + template + class Fde_addresses + { + public: + typedef typename elfcpp::Elf_types::Elf_Addr Address; + typedef typename std::pair Fde_address; + typedef typename std::vector Fde_address_list; + typedef typename Fde_address_list::iterator iterator; + + Fde_addresses(unsigned int reserve) + : fde_addresses_() + { this->fde_addresses_.reserve(reserve); } + + void + push_back(Address pc_address, Address fde_address) + { + this->fde_addresses_.push_back(std::make_pair(pc_address, fde_address)); + } + + iterator + begin() + { return this->fde_addresses_.begin(); } + + iterator + end() + { return this->fde_addresses_.end(); } + + private: + Fde_address_list fde_addresses_; + }; + + // Compare Fde_address objects. + template + struct Fde_address_compare + { + bool + operator()(const typename Fde_addresses::Fde_address& f1, + const typename Fde_addresses::Fde_address& f2) const + { return f1.first < f2.first; } + }; + + // Return the PC to which an FDE refers. + template + typename elfcpp::Elf_types::Elf_Addr + get_fde_pc(typename elfcpp::Elf_types::Elf_Addr eh_frame_address, + const unsigned char* eh_frame_contents, + section_offset_type fde_offset, unsigned char fde_encoding); + + // Convert Fde_offsets to Fde_addresses. + template + void + get_fde_addresses(Output_file* of, + const Fde_offsets* fde_offsets, + Fde_addresses* fde_addresses); + + // The .eh_frame section. + Output_section* eh_frame_section_; + // The .eh_frame section data. + const Eh_frame* eh_frame_data_; + // Data from the FDEs in the .eh_frame sections. + Fde_offsets fde_offsets_; + // Whether we found any .eh_frame sections which we could not + // process. + bool any_unrecognized_eh_frame_sections_; +}; + +// This class holds an FDE. + +class Fde +{ + public: + Fde(Relobj* object, unsigned int shndx, section_offset_type input_offset, + const unsigned char* contents, size_t length) + : object_(object), + contents_(reinterpret_cast(contents), length) + { + this->u_.from_object.shndx = shndx; + this->u_.from_object.input_offset = input_offset; + } + + // Create an FDE associated with a PLT. + Fde(Output_data* plt, const unsigned char* contents, size_t length, + bool post_map) + : object_(NULL), + contents_(reinterpret_cast(contents), length) + { + this->u_.from_linker.plt = plt; + this->u_.from_linker.post_map = post_map; + } + + // Return the length of this FDE. Add 4 for the length and 4 for + // the offset to the CIE. + size_t + length() const + { return this->contents_.length() + 8; } + + // Add a mapping for this FDE to MERGE_MAP, so that relocations + // against the FDE are applied to right part of the output file. + void + add_mapping(section_offset_type output_offset, Merge_map* merge_map) const + { + if (this->object_ != NULL) + merge_map->add_mapping(this->object_, this->u_.from_object.shndx, + this->u_.from_object.input_offset, this->length(), + output_offset); + } + + // Return whether this FDE was added after merge mapping. + bool + post_map() + { return this->object_ == NULL && this->u_.from_linker.post_map; } + + // Write the FDE to OVIEW starting at OFFSET. FDE_ENCODING is the + // encoding, from the CIE. Round up the bytes to ADDRALIGN if + // necessary. ADDRESS is the virtual address of OVIEW. Record the + // FDE in EH_FRAME_HDR. Return the new offset. + template + section_offset_type + write(unsigned char* oview, section_offset_type offset, + uint64_t address, unsigned int addralign, + section_offset_type cie_offset, unsigned char fde_encoding, + Eh_frame_hdr* eh_frame_hdr); + + private: + // The object in which this FDE was seen. This will be NULL for a + // linker generated FDE. + Relobj* object_; + union + { + // These fields are used if the FDE is from an input object (the + // object_ field is not NULL). + struct + { + // Input section index for this FDE. + unsigned int shndx; + // Offset within the input section for this FDE. + section_offset_type input_offset; + } from_object; + // This field is used if the FDE is generated by the linker (the + // object_ field is NULL). + struct + { + // The only linker generated FDEs are for PLT sections, and this + // points to the PLT section. + Output_data* plt; + // Set if the FDE was added after merge mapping. + bool post_map; + } from_linker; + } u_; + // FDE data. + std::string contents_; +}; + +// A FDE plus some info from a CIE to allow later writing of the FDE. + +struct Post_fde +{ + Post_fde(Fde* f, section_offset_type cie_off, unsigned char encoding) + : fde(f), cie_offset(cie_off), fde_encoding(encoding) + { } + + Fde* fde; + section_offset_type cie_offset; + unsigned char fde_encoding; +}; + +typedef std::vector Post_fdes; + +// This class holds a CIE. + +class Cie +{ + public: + Cie(Relobj* object, unsigned int shndx, section_offset_type input_offset, + unsigned char fde_encoding, const char* personality_name, + const unsigned char* contents, size_t length) + : object_(object), + shndx_(shndx), + input_offset_(input_offset), + fde_encoding_(fde_encoding), + personality_name_(personality_name), + fdes_(), + contents_(reinterpret_cast(contents), length) + { } + + ~Cie(); + + // We permit copying a CIE when there are no FDEs. This is + // convenient in the code which creates them. + Cie(const Cie& cie) + : object_(cie.object_), + shndx_(cie.shndx_), + input_offset_(cie.input_offset_), + fde_encoding_(cie.fde_encoding_), + personality_name_(cie.personality_name_), + fdes_(), + contents_(cie.contents_) + { gold_assert(cie.fdes_.empty()); } + + // Add an FDE associated with this CIE. + void + add_fde(Fde* fde) + { this->fdes_.push_back(fde); } + + // Return the number of FDEs. + unsigned int + fde_count() const + { return this->fdes_.size(); } + + // Set the output offset of this CIE to OUTPUT_OFFSET. It will be + // followed by all its FDEs. ADDRALIGN is the required address + // alignment, typically 4 or 8. This updates MERGE_MAP with the + // mapping. It returns the new output offset. + section_offset_type + set_output_offset(section_offset_type output_offset, unsigned int addralign, + Merge_map*); + + // Write the CIE to OVIEW starting at OFFSET. Round up the bytes to + // ADDRALIGN. ADDRESS is the virtual address of OVIEW. + // EH_FRAME_HDR is the exception frame header for FDE recording. + // POST_FDES stashes FDEs created after mappings were done, for later + // writing. Return the new offset. + template + section_offset_type + write(unsigned char* oview, section_offset_type offset, uint64_t address, + unsigned int addralign, Eh_frame_hdr* eh_frame_hdr, + Post_fdes* post_fdes); + + friend bool operator<(const Cie&, const Cie&); + friend bool operator==(const Cie&, const Cie&); + + private: + // The class is not assignable. + Cie& operator=(const Cie&); + + // The object in which this CIE was first seen. This will be NULL + // for a linker generated CIE. + Relobj* object_; + // Input section index for this CIE. This will be 0 for a linker + // generated CIE. + unsigned int shndx_; + // Offset within the input section for this CIE. This will be 0 for + // a linker generated CIE. + section_offset_type input_offset_; + // The encoding of the FDE. This is a DW_EH_PE code. + unsigned char fde_encoding_; + // The name of the personality routine. This will be the name of a + // global symbol, or will be the empty string. + std::string personality_name_; + // List of FDEs. + std::vector fdes_; + // CIE data. + std::string contents_; +}; + +extern bool operator<(const Cie&, const Cie&); +extern bool operator==(const Cie&, const Cie&); + +// This class manages .eh_frame sections. It discards duplicate +// exception information. + +class Eh_frame : public Output_section_data +{ + public: + Eh_frame(); + + // Record the associated Eh_frame_hdr, if any. + void + set_eh_frame_hdr(Eh_frame_hdr* hdr) + { this->eh_frame_hdr_ = hdr; } + + // Add the input section SHNDX in OBJECT. SYMBOLS is the contents + // of the symbol table section (size SYMBOLS_SIZE), SYMBOL_NAMES is + // the symbol names section (size SYMBOL_NAMES_SIZE). RELOC_SHNDX + // is the relocation section if any (0 for none, -1U for multiple). + // RELOC_TYPE is the type of the relocation section if any. This + // returns whether the section was incorporated into the .eh_frame + // data. + template + bool + add_ehframe_input_section(Sized_relobj_file* object, + const unsigned char* symbols, + section_size_type symbols_size, + const unsigned char* symbol_names, + section_size_type symbol_names_size, + unsigned int shndx, unsigned int reloc_shndx, + unsigned int reloc_type); + + // Add a CIE and an FDE for a PLT section, to permit unwinding + // through a PLT. The FDE data should start with 8 bytes of zero, + // which will be replaced by a 4 byte PC relative reference to the + // address of PLT and a 4 byte size of PLT. + void + add_ehframe_for_plt(Output_data* plt, const unsigned char* cie_data, + size_t cie_length, const unsigned char* fde_data, + size_t fde_length); + + // Return the number of FDEs. + unsigned int + fde_count() const; + + protected: + // Set the final data size. + void + set_final_data_size(); + + // Return the output address for an input address. + bool + do_output_offset(const Relobj*, unsigned int shndx, + section_offset_type offset, + section_offset_type* poutput) const; + + // Return whether this is the merge section for an input section. + bool + do_is_merge_section_for(const Relobj*, unsigned int shndx) const; + + // Write the data to the file. + void + do_write(Output_file*); + + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _("** eh_frame")); } + + private: + // The comparison routine for the CIE map. + struct Cie_less + { + bool + operator()(const Cie* cie1, const Cie* cie2) const + { return *cie1 < *cie2; } + }; + + // A set of unique CIEs. + typedef std::set Cie_offsets; + + // A list of unmergeable CIEs. + typedef std::vector Unmergeable_cie_offsets; + + // A mapping from offsets to CIEs. This is used while reading an + // input section. + typedef std::map Offsets_to_cie; + + // A list of CIEs, and a bool indicating whether the CIE is + // mergeable. + typedef std::vector > New_cies; + + // Skip an LEB128. + static bool + skip_leb128(const unsigned char**, const unsigned char*); + + // The implementation of add_ehframe_input_section. + template + bool + do_add_ehframe_input_section(Sized_relobj_file* object, + const unsigned char* symbols, + section_size_type symbols_size, + const unsigned char* symbol_names, + section_size_type symbol_names_size, + unsigned int shndx, + unsigned int reloc_shndx, + unsigned int reloc_type, + const unsigned char* pcontents, + section_size_type contents_len, + New_cies*); + + // Read a CIE. + template + bool + read_cie(Sized_relobj_file* object, + unsigned int shndx, + const unsigned char* symbols, + section_size_type symbols_size, + const unsigned char* symbol_names, + section_size_type symbol_names_size, + const unsigned char* pcontents, + const unsigned char* pcie, + const unsigned char* pcieend, + Track_relocs* relocs, + Offsets_to_cie* cies, + New_cies* new_cies); + + // Read an FDE. + template + bool + read_fde(Sized_relobj_file* object, + unsigned int shndx, + const unsigned char* symbols, + section_size_type symbols_size, + const unsigned char* pcontents, + unsigned int offset, + const unsigned char* pfde, + const unsigned char* pfdeend, + Track_relocs* relocs, + Offsets_to_cie* cies); + + // Template version of write function. + template + void + do_sized_write(unsigned char* oview); + + // The exception frame header, if any. + Eh_frame_hdr* eh_frame_hdr_; + // A mapping from all unique CIEs to their offset in the output + // file. + Cie_offsets cie_offsets_; + // A mapping from unmergeable CIEs to their offset in the output + // file. + Unmergeable_cie_offsets unmergeable_cie_offsets_; + // A mapping from input sections to the output section. + Merge_map merge_map_; + // Whether we have created the mappings to the output section. + bool mappings_are_done_; + // The final data size. This is only set if mappings_are_done_ is + // true. + section_size_type final_data_size_; +}; + +} // End namespace gold. + +#endif // !defined(GOLD_EHFRAME_H) diff --git a/binutils-2.25/gold/errors.cc b/binutils-2.25/gold/errors.cc new file mode 100644 index 00000000..b79764bd --- /dev/null +++ b/binutils-2.25/gold/errors.cc @@ -0,0 +1,420 @@ +// errors.cc -- handle errors for gold + +// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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 +#include + +#include "gold-threads.h" +#include "parameters.h" +#include "object.h" +#include "symtab.h" +#include "errors.h" + +namespace gold +{ + +// Class Errors. + +const int Errors::max_undefined_error_report; + +Errors::Errors(const char* program_name) + : program_name_(program_name), lock_(NULL), initialize_lock_(&this->lock_), + error_count_(0), warning_count_(0), undefined_symbols_() +{ +} + +// Initialize the lock_ field. If we have not yet processed the +// parameters, then we can't initialize, since we don't yet know +// whether we are using threads. That is OK, since if we haven't +// processed the parameters, we haven't created any threads, and we +// don't need a lock. Return true if the lock is now initialized. + +bool +Errors::initialize_lock() +{ + return this->initialize_lock_.initialize(); +} + +// Increment a counter, holding the lock if available. + +void +Errors::increment_counter(int *counter) +{ + if (!this->initialize_lock()) + { + // The lock does not exist, which means that we don't need it. + ++*counter; + } + else + { + Hold_lock h(*this->lock_); + ++*counter; + } +} + +// Report a fatal error. + +void +Errors::fatal(const char* format, va_list args) +{ + fprintf(stderr, _("%s: fatal error: "), this->program_name_); + vfprintf(stderr, format, args); + fputc('\n', stderr); + gold_exit(GOLD_ERR); +} + +// Report a fallback error. + +void +Errors::fallback(const char* format, va_list args) +{ + fprintf(stderr, _("%s: fatal error: "), this->program_name_); + vfprintf(stderr, format, args); + fputc('\n', stderr); + gold_exit(GOLD_FALLBACK); +} + +// Report an error. + +void +Errors::error(const char* format, va_list args) +{ + fprintf(stderr, _("%s: error: "), this->program_name_); + vfprintf(stderr, format, args); + fputc('\n', stderr); + + this->increment_counter(&this->error_count_); +} + +// Report a warning. + +void +Errors::warning(const char* format, va_list args) +{ + fprintf(stderr, _("%s: warning: "), this->program_name_); + vfprintf(stderr, format, args); + fputc('\n', stderr); + + this->increment_counter(&this->warning_count_); +} + +// Print an informational message. + +void +Errors::info(const char* format, va_list args) +{ + vfprintf(stderr, format, args); + fputc('\n', stderr); +} + +// Report an error at a reloc location. + +template +void +Errors::error_at_location(const Relocate_info* relinfo, + size_t relnum, off_t reloffset, + const char* format, va_list args) +{ + fprintf(stderr, _("%s: error: "), + relinfo->location(relnum, reloffset).c_str()); + vfprintf(stderr, format, args); + fputc('\n', stderr); + + this->increment_counter(&this->error_count_); +} + +// Report a warning at a reloc location. + +template +void +Errors::warning_at_location(const Relocate_info* relinfo, + size_t relnum, off_t reloffset, + const char* format, va_list args) +{ + fprintf(stderr, _("%s: warning: "), + relinfo->location(relnum, reloffset).c_str()); + vfprintf(stderr, format, args); + fputc('\n', stderr); + + this->increment_counter(&this->warning_count_); +} + +// Issue an undefined symbol error with a caller-supplied location string. + +void +Errors::undefined_symbol(const Symbol* sym, const std::string& location) +{ + bool initialized = this->initialize_lock(); + gold_assert(initialized); + + const char* zmsg; + { + Hold_lock h(*this->lock_); + if (++this->undefined_symbols_[sym] >= max_undefined_error_report) + return; + if (parameters->options().warn_unresolved_symbols()) + { + ++this->warning_count_; + zmsg = _("warning"); + } + else + { + ++this->error_count_; + zmsg = _("error"); + } + } + + const char* const version = sym->version(); + if (version == NULL) + fprintf(stderr, _("%s: %s: undefined reference to '%s'\n"), + location.c_str(), zmsg, sym->demangled_name().c_str()); + else + fprintf(stderr, + _("%s: %s: undefined reference to '%s', version '%s'\n"), + location.c_str(), zmsg, sym->demangled_name().c_str(), version); +} + +// Issue a debugging message. + +void +Errors::debug(const char* format, ...) +{ + fprintf(stderr, _("%s: "), this->program_name_); + + va_list args; + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + + fputc('\n', stderr); +} + +// The functions which the rest of the code actually calls. + +// Report a fatal error. + +void +gold_fatal(const char* format, ...) +{ + va_list args; + va_start(args, format); + parameters->errors()->fatal(format, args); + va_end(args); +} + +// Report a fallback error. + +void +gold_fallback(const char* format, ...) +{ + va_list args; + va_start(args, format); + parameters->errors()->fallback(format, args); + va_end(args); +} + +// Report an error. + +void +gold_error(const char* format, ...) +{ + va_list args; + va_start(args, format); + parameters->errors()->error(format, args); + va_end(args); +} + +// Report a warning. + +void +gold_warning(const char* format, ...) +{ + va_list args; + va_start(args, format); + parameters->errors()->warning(format, args); + va_end(args); +} + +// Print an informational message. + +void +gold_info(const char* format, ...) +{ + va_list args; + va_start(args, format); + parameters->errors()->info(format, args); + va_end(args); +} + +// Report an error at a location. + +template +void +gold_error_at_location(const Relocate_info* relinfo, + size_t relnum, off_t reloffset, + const char* format, ...) +{ + va_list args; + va_start(args, format); + parameters->errors()->error_at_location(relinfo, relnum, reloffset, + format, args); + va_end(args); +} + +// Report a warning at a location. + +template +void +gold_warning_at_location(const Relocate_info* relinfo, + size_t relnum, off_t reloffset, + const char* format, ...) +{ + va_list args; + va_start(args, format); + parameters->errors()->warning_at_location(relinfo, relnum, reloffset, + format, args); + va_end(args); +} + +// Report an undefined symbol. + +void +gold_undefined_symbol(const Symbol* sym) +{ + parameters->errors()->undefined_symbol(sym, sym->object()->name().c_str()); +} + +// Report an undefined symbol at a reloc location + +template +void +gold_undefined_symbol_at_location(const Symbol* sym, + const Relocate_info* relinfo, + size_t relnum, off_t reloffset) +{ + parameters->errors()->undefined_symbol(sym, + relinfo->location(relnum, reloffset)); +} + +#ifdef HAVE_TARGET_32_LITTLE +template +void +gold_error_at_location<32, false>(const Relocate_info<32, false>* relinfo, + size_t relnum, off_t reloffset, + const char* format, ...); +#endif + +#ifdef HAVE_TARGET_32_BIG +template +void +gold_error_at_location<32, true>(const Relocate_info<32, true>* relinfo, + size_t relnum, off_t reloffset, + const char* format, ...); +#endif + +#ifdef HAVE_TARGET_64_LITTLE +template +void +gold_error_at_location<64, false>(const Relocate_info<64, false>* relinfo, + size_t relnum, off_t reloffset, + const char* format, ...); +#endif + +#ifdef HAVE_TARGET_64_BIG +template +void +gold_error_at_location<64, true>(const Relocate_info<64, true>* relinfo, + size_t relnum, off_t reloffset, + const char* format, ...); +#endif + +#ifdef HAVE_TARGET_32_LITTLE +template +void +gold_warning_at_location<32, false>(const Relocate_info<32, false>* relinfo, + size_t relnum, off_t reloffset, + const char* format, ...); +#endif + +#ifdef HAVE_TARGET_32_BIG +template +void +gold_warning_at_location<32, true>(const Relocate_info<32, true>* relinfo, + size_t relnum, off_t reloffset, + const char* format, ...); +#endif + +#ifdef HAVE_TARGET_64_LITTLE +template +void +gold_warning_at_location<64, false>(const Relocate_info<64, false>* relinfo, + size_t relnum, off_t reloffset, + const char* format, ...); +#endif + +#ifdef HAVE_TARGET_64_BIG +template +void +gold_warning_at_location<64, true>(const Relocate_info<64, true>* relinfo, + size_t relnum, off_t reloffset, + const char* format, ...); +#endif + +#ifdef HAVE_TARGET_32_LITTLE +template +void +gold_undefined_symbol_at_location<32, false>( + const Symbol* sym, + const Relocate_info<32, false>* relinfo, + size_t relnum, off_t reloffset); +#endif + +#ifdef HAVE_TARGET_32_BIG +template +void +gold_undefined_symbol_at_location<32, true>( + const Symbol* sym, + const Relocate_info<32, true>* relinfo, + size_t relnum, off_t reloffset); +#endif + +#ifdef HAVE_TARGET_64_LITTLE +template +void +gold_undefined_symbol_at_location<64, false>( + const Symbol* sym, + const Relocate_info<64, false>* relinfo, + size_t relnum, off_t reloffset); +#endif + +#ifdef HAVE_TARGET_64_BIG +template +void +gold_undefined_symbol_at_location<64, true>( + const Symbol* sym, + const Relocate_info<64, true>* relinfo, + size_t relnum, off_t reloffset); +#endif + +} // End namespace gold. diff --git a/binutils-2.25/gold/errors.h b/binutils-2.25/gold/errors.h new file mode 100644 index 00000000..1e61c8db --- /dev/null +++ b/binutils-2.25/gold/errors.h @@ -0,0 +1,138 @@ +// errors.h -- handle errors for gold -*- C++ -*- + +// Copyright 2006, 2007, 2008 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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. + +#ifndef GOLD_ERRORS_H +#define GOLD_ERRORS_H + +#include + +#include "gold-threads.h" + +namespace gold +{ + +class Symbol; +template +struct Relocate_info; + +// This class handles errors for gold. There is a single instance +// which is used by all threads. If and when we make the gold code +// more amenable to being used in a library, we will make this an +// abstract interface class, and expect the caller to provide their +// own instantiation. + +class Errors +{ + public: + Errors(const char* program_name); + + // Report a fatal error. After printing the error, this must exit. + void + fatal(const char* format, va_list) ATTRIBUTE_NORETURN; + + // Report a fallback error. After printing the error, this must exit + // with a special status code indicating that fallback to + // --incremental-full is required. + void + fallback(const char* format, va_list) ATTRIBUTE_NORETURN; + + // Report an error and continue. + void + error(const char* format, va_list); + + // Report a warning and continue. + void + warning(const char* format, va_list); + + // Print an informational message and continue. + void + info(const char* format, va_list); + + // Report an error at a reloc location. + template + void + error_at_location(const Relocate_info* relinfo, + size_t relnum, off_t reloffset, + const char* format, va_list); + + // Report a warning at a reloc location. + template + void + warning_at_location(const Relocate_info* relinfo, + size_t relnum, off_t reloffset, + const char* format, va_list); + + // Issue an undefined symbol error. LOCATION is the location of + // the error (typically an object file name or relocation info). + void + undefined_symbol(const Symbol* sym, const std::string& location); + + // Report a debugging message. + void + debug(const char* format, ...) ATTRIBUTE_PRINTF_2; + + // Return the number of errors. + int + error_count() const + { return this->error_count_; } + + // Return the number of warnings. + int + warning_count() const + { return this->warning_count_; } + + private: + Errors(const Errors&); + Errors& operator=(const Errors&); + + // Initialize the lock. We don't do this in the constructor because + // lock initialization wants to know whether we are using threads or + // not. This returns true if the lock is now initialized. + bool + initialize_lock(); + + // Increment a counter, holding the lock. + void + increment_counter(int*); + + // The number of times we report an undefined symbol. + static const int max_undefined_error_report = 5; + + // The name of the program. + const char* program_name_; + // This class can be accessed from multiple threads. This lock is + // used to control access to the data structures. + Lock* lock_; + // Used to initialize the lock_ field exactly once. + Initialize_lock initialize_lock_; + // Numbers of errors reported. + int error_count_; + // Number of warnings reported. + int warning_count_; + // A map counting the numbers of times we have seen an undefined + // symbol. + Unordered_map undefined_symbols_; +}; + +} // End namespace gold. + +#endif // !defined(GOLD_ERRORS_H) diff --git a/binutils-2.25/gold/expression.cc b/binutils-2.25/gold/expression.cc new file mode 100644 index 00000000..e31c151c --- /dev/null +++ b/binutils-2.25/gold/expression.cc @@ -0,0 +1,1273 @@ +// expression.cc -- expressions in linker scripts for gold + +// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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 + +#include "elfcpp.h" +#include "parameters.h" +#include "symtab.h" +#include "layout.h" +#include "output.h" +#include "script.h" +#include "script-c.h" + +namespace gold +{ + +// This file holds the code which handles linker expressions. + +// The dot symbol, which linker scripts refer to simply as ".", +// requires special treatment. The dot symbol is set several times, +// section addresses will refer to it, output sections will change it, +// and it can be set based on the value of other symbols. We simplify +// the handling by prohibiting setting the dot symbol to the value of +// a non-absolute symbol. + +// When evaluating the value of an expression, we pass in a pointer to +// this struct, so that the expression evaluation can find the +// information it needs. + +struct Expression::Expression_eval_info +{ + // The symbol table. + const Symbol_table* symtab; + // The layout--we use this to get section information. + const Layout* layout; + // Whether to check assertions. + bool check_assertions; + // Whether expressions can refer to the dot symbol. The dot symbol + // is only available within a SECTIONS clause. + bool is_dot_available; + // The current value of the dot symbol. + uint64_t dot_value; + // The section in which the dot symbol is defined; this is NULL if + // it is absolute. + Output_section* dot_section; + // Points to where the section of the result should be stored. + Output_section** result_section_pointer; + // Pointer to where the alignment of the result should be stored. + uint64_t* result_alignment_pointer; +}; + +// Evaluate an expression. + +uint64_t +Expression::eval(const Symbol_table* symtab, const Layout* layout, + bool check_assertions) +{ + return this->eval_maybe_dot(symtab, layout, check_assertions, + false, 0, NULL, NULL, NULL, false); +} + +// Evaluate an expression which may refer to the dot symbol. + +uint64_t +Expression::eval_with_dot(const Symbol_table* symtab, const Layout* layout, + bool check_assertions, uint64_t dot_value, + Output_section* dot_section, + Output_section** result_section_pointer, + uint64_t* result_alignment_pointer, + bool is_section_dot_assignment) +{ + return this->eval_maybe_dot(symtab, layout, check_assertions, true, + dot_value, dot_section, result_section_pointer, + result_alignment_pointer, + is_section_dot_assignment); +} + +// Evaluate an expression which may or may not refer to the dot +// symbol. + +uint64_t +Expression::eval_maybe_dot(const Symbol_table* symtab, const Layout* layout, + bool check_assertions, bool is_dot_available, + uint64_t dot_value, Output_section* dot_section, + Output_section** result_section_pointer, + uint64_t* result_alignment_pointer, + bool is_section_dot_assignment) +{ + Expression_eval_info eei; + eei.symtab = symtab; + eei.layout = layout; + eei.check_assertions = check_assertions; + eei.is_dot_available = is_dot_available; + eei.dot_value = dot_value; + eei.dot_section = dot_section; + + // We assume the value is absolute, and only set this to a section + // if we find a section-relative reference. + if (result_section_pointer != NULL) + *result_section_pointer = NULL; + eei.result_section_pointer = result_section_pointer; + + eei.result_alignment_pointer = result_alignment_pointer; + + uint64_t val = this->value(&eei); + + // If this is an assignment to dot within a section, and the value + // is absolute, treat it as a section-relative offset. + if (is_section_dot_assignment && *result_section_pointer == NULL) + { + gold_assert(dot_section != NULL); + val += dot_section->address(); + *result_section_pointer = dot_section; + } + return val; +} + +// A number. + +class Integer_expression : public Expression +{ + public: + Integer_expression(uint64_t val) + : val_(val) + { } + + uint64_t + value(const Expression_eval_info*) + { return this->val_; } + + void + print(FILE* f) const + { fprintf(f, "0x%llx", static_cast(this->val_)); } + + private: + uint64_t val_; +}; + +extern "C" Expression* +script_exp_integer(uint64_t val) +{ + return new Integer_expression(val); +} + +// An expression whose value is the value of a symbol. + +class Symbol_expression : public Expression +{ + public: + Symbol_expression(const char* name, size_t length) + : name_(name, length) + { } + + uint64_t + value(const Expression_eval_info*); + + void + print(FILE* f) const + { fprintf(f, "%s", this->name_.c_str()); } + + private: + std::string name_; +}; + +uint64_t +Symbol_expression::value(const Expression_eval_info* eei) +{ + Symbol* sym = eei->symtab->lookup(this->name_.c_str()); + if (sym == NULL || !sym->is_defined()) + { + gold_error(_("undefined symbol '%s' referenced in expression"), + this->name_.c_str()); + return 0; + } + + if (eei->result_section_pointer != NULL) + *eei->result_section_pointer = sym->output_section(); + + if (parameters->target().get_size() == 32) + return eei->symtab->get_sized_symbol<32>(sym)->value(); + else if (parameters->target().get_size() == 64) + return eei->symtab->get_sized_symbol<64>(sym)->value(); + else + gold_unreachable(); +} + +// An expression whose value is the value of the special symbol ".". +// This is only valid within a SECTIONS clause. + +class Dot_expression : public Expression +{ + public: + Dot_expression() + { } + + uint64_t + value(const Expression_eval_info*); + + void + print(FILE* f) const + { fprintf(f, "."); } +}; + +uint64_t +Dot_expression::value(const Expression_eval_info* eei) +{ + if (!eei->is_dot_available) + { + gold_error(_("invalid reference to dot symbol outside of " + "SECTIONS clause")); + return 0; + } + if (eei->result_section_pointer != NULL) + *eei->result_section_pointer = eei->dot_section; + return eei->dot_value; +} + +// A string. This is either the name of a symbol, or ".". + +extern "C" Expression* +script_exp_string(const char* name, size_t length) +{ + if (length == 1 && name[0] == '.') + return new Dot_expression(); + else + return new Symbol_expression(name, length); +} + +// A unary expression. + +class Unary_expression : public Expression +{ + public: + Unary_expression(Expression* arg) + : arg_(arg) + { } + + ~Unary_expression() + { delete this->arg_; } + + protected: + uint64_t + arg_value(const Expression_eval_info* eei, + Output_section** arg_section_pointer) const + { + return this->arg_->eval_maybe_dot(eei->symtab, eei->layout, + eei->check_assertions, + eei->is_dot_available, + eei->dot_value, + eei->dot_section, + arg_section_pointer, + eei->result_alignment_pointer, + false); + } + + void + arg_print(FILE* f) const + { this->arg_->print(f); } + + private: + Expression* arg_; +}; + +// Handle unary operators. We use a preprocessor macro as a hack to +// capture the C operator. + +#define UNARY_EXPRESSION(NAME, OPERATOR) \ + class Unary_ ## NAME : public Unary_expression \ + { \ + public: \ + Unary_ ## NAME(Expression* arg) \ + : Unary_expression(arg) \ + { } \ + \ + uint64_t \ + value(const Expression_eval_info* eei) \ + { \ + Output_section* arg_section; \ + uint64_t ret = OPERATOR this->arg_value(eei, &arg_section); \ + if (arg_section != NULL && parameters->options().relocatable()) \ + gold_warning(_("unary " #NAME " applied to section " \ + "relative value")); \ + return ret; \ + } \ + \ + void \ + print(FILE* f) const \ + { \ + fprintf(f, "(%s ", #OPERATOR); \ + this->arg_print(f); \ + fprintf(f, ")"); \ + } \ + }; \ + \ + extern "C" Expression* \ + script_exp_unary_ ## NAME(Expression* arg) \ + { \ + return new Unary_ ## NAME(arg); \ + } + +UNARY_EXPRESSION(minus, -) +UNARY_EXPRESSION(logical_not, !) +UNARY_EXPRESSION(bitwise_not, ~) + +// A binary expression. + +class Binary_expression : public Expression +{ + public: + Binary_expression(Expression* left, Expression* right) + : left_(left), right_(right) + { } + + ~Binary_expression() + { + delete this->left_; + delete this->right_; + } + + protected: + uint64_t + left_value(const Expression_eval_info* eei, + Output_section** section_pointer, + uint64_t* alignment_pointer) const + { + return this->left_->eval_maybe_dot(eei->symtab, eei->layout, + eei->check_assertions, + eei->is_dot_available, + eei->dot_value, + eei->dot_section, + section_pointer, + alignment_pointer, + false); + } + + uint64_t + right_value(const Expression_eval_info* eei, + Output_section** section_pointer, + uint64_t* alignment_pointer) const + { + return this->right_->eval_maybe_dot(eei->symtab, eei->layout, + eei->check_assertions, + eei->is_dot_available, + eei->dot_value, + eei->dot_section, + section_pointer, + alignment_pointer, + false); + } + + void + left_print(FILE* f) const + { this->left_->print(f); } + + void + right_print(FILE* f) const + { this->right_->print(f); } + + // This is a call to function FUNCTION_NAME. Print it. This is for + // debugging. + void + print_function(FILE* f, const char* function_name) const + { + fprintf(f, "%s(", function_name); + this->left_print(f); + fprintf(f, ", "); + this->right_print(f); + fprintf(f, ")"); + } + + private: + Expression* left_; + Expression* right_; +}; + +// Handle binary operators. We use a preprocessor macro as a hack to +// capture the C operator. KEEP_LEFT means that if the left operand +// is section relative and the right operand is not, the result uses +// the same section as the left operand. KEEP_RIGHT is the same with +// left and right swapped. IS_DIV means that we need to give an error +// if the right operand is zero. WARN means that we should warn if +// used on section relative values in a relocatable link. We always +// warn if used on values in different sections in a relocatable link. + +#define BINARY_EXPRESSION(NAME, OPERATOR, KEEP_LEFT, KEEP_RIGHT, IS_DIV, WARN) \ + class Binary_ ## NAME : public Binary_expression \ + { \ + public: \ + Binary_ ## NAME(Expression* left, Expression* right) \ + : Binary_expression(left, right) \ + { } \ + \ + uint64_t \ + value(const Expression_eval_info* eei) \ + { \ + Output_section* left_section; \ + uint64_t left_alignment = 0; \ + uint64_t left = this->left_value(eei, &left_section, \ + &left_alignment); \ + Output_section* right_section; \ + uint64_t right_alignment = 0; \ + uint64_t right = this->right_value(eei, &right_section, \ + &right_alignment); \ + if (KEEP_RIGHT && left_section == NULL && right_section != NULL) \ + { \ + if (eei->result_section_pointer != NULL) \ + *eei->result_section_pointer = right_section; \ + if (eei->result_alignment_pointer != NULL \ + && right_alignment > *eei->result_alignment_pointer) \ + *eei->result_alignment_pointer = right_alignment; \ + } \ + else if (KEEP_LEFT \ + && left_section != NULL \ + && right_section == NULL) \ + { \ + if (eei->result_section_pointer != NULL) \ + *eei->result_section_pointer = left_section; \ + if (eei->result_alignment_pointer != NULL \ + && left_alignment > *eei->result_alignment_pointer) \ + *eei->result_alignment_pointer = left_alignment; \ + } \ + else if ((WARN || left_section != right_section) \ + && (left_section != NULL || right_section != NULL) \ + && parameters->options().relocatable()) \ + gold_warning(_("binary " #NAME " applied to section " \ + "relative value")); \ + if (IS_DIV && right == 0) \ + { \ + gold_error(_(#NAME " by zero")); \ + return 0; \ + } \ + return left OPERATOR right; \ + } \ + \ + void \ + print(FILE* f) const \ + { \ + fprintf(f, "("); \ + this->left_print(f); \ + fprintf(f, " %s ", #OPERATOR); \ + this->right_print(f); \ + fprintf(f, ")"); \ + } \ + }; \ + \ + extern "C" Expression* \ + script_exp_binary_ ## NAME(Expression* left, Expression* right) \ + { \ + return new Binary_ ## NAME(left, right); \ + } + +BINARY_EXPRESSION(mult, *, false, false, false, true) +BINARY_EXPRESSION(div, /, false, false, true, true) +BINARY_EXPRESSION(mod, %, false, false, true, true) +BINARY_EXPRESSION(add, +, true, true, false, true) +BINARY_EXPRESSION(sub, -, true, false, false, false) +BINARY_EXPRESSION(lshift, <<, false, false, false, true) +BINARY_EXPRESSION(rshift, >>, false, false, false, true) +BINARY_EXPRESSION(eq, ==, false, false, false, false) +BINARY_EXPRESSION(ne, !=, false, false, false, false) +BINARY_EXPRESSION(le, <=, false, false, false, false) +BINARY_EXPRESSION(ge, >=, false, false, false, false) +BINARY_EXPRESSION(lt, <, false, false, false, false) +BINARY_EXPRESSION(gt, >, false, false, false, false) +BINARY_EXPRESSION(bitwise_and, &, true, true, false, true) +BINARY_EXPRESSION(bitwise_xor, ^, true, true, false, true) +BINARY_EXPRESSION(bitwise_or, |, true, true, false, true) +BINARY_EXPRESSION(logical_and, &&, false, false, false, true) +BINARY_EXPRESSION(logical_or, ||, false, false, false, true) + +// A trinary expression. + +class Trinary_expression : public Expression +{ + public: + Trinary_expression(Expression* arg1, Expression* arg2, Expression* arg3) + : arg1_(arg1), arg2_(arg2), arg3_(arg3) + { } + + ~Trinary_expression() + { + delete this->arg1_; + delete this->arg2_; + delete this->arg3_; + } + + protected: + uint64_t + arg1_value(const Expression_eval_info* eei, + Output_section** section_pointer) const + { + return this->arg1_->eval_maybe_dot(eei->symtab, eei->layout, + eei->check_assertions, + eei->is_dot_available, + eei->dot_value, + eei->dot_section, + section_pointer, + NULL, + false); + } + + uint64_t + arg2_value(const Expression_eval_info* eei, + Output_section** section_pointer, + uint64_t* alignment_pointer) const + { + return this->arg1_->eval_maybe_dot(eei->symtab, eei->layout, + eei->check_assertions, + eei->is_dot_available, + eei->dot_value, + eei->dot_section, + section_pointer, + alignment_pointer, + false); + } + + uint64_t + arg3_value(const Expression_eval_info* eei, + Output_section** section_pointer, + uint64_t* alignment_pointer) const + { + return this->arg1_->eval_maybe_dot(eei->symtab, eei->layout, + eei->check_assertions, + eei->is_dot_available, + eei->dot_value, + eei->dot_section, + section_pointer, + alignment_pointer, + false); + } + + void + arg1_print(FILE* f) const + { this->arg1_->print(f); } + + void + arg2_print(FILE* f) const + { this->arg2_->print(f); } + + void + arg3_print(FILE* f) const + { this->arg3_->print(f); } + + private: + Expression* arg1_; + Expression* arg2_; + Expression* arg3_; +}; + +// The conditional operator. + +class Trinary_cond : public Trinary_expression +{ + public: + Trinary_cond(Expression* arg1, Expression* arg2, Expression* arg3) + : Trinary_expression(arg1, arg2, arg3) + { } + + uint64_t + value(const Expression_eval_info* eei) + { + Output_section* arg1_section; + uint64_t arg1 = this->arg1_value(eei, &arg1_section); + return (arg1 + ? this->arg2_value(eei, eei->result_section_pointer, + eei->result_alignment_pointer) + : this->arg3_value(eei, eei->result_section_pointer, + eei->result_alignment_pointer)); + } + + void + print(FILE* f) const + { + fprintf(f, "("); + this->arg1_print(f); + fprintf(f, " ? "); + this->arg2_print(f); + fprintf(f, " : "); + this->arg3_print(f); + fprintf(f, ")"); + } +}; + +extern "C" Expression* +script_exp_trinary_cond(Expression* arg1, Expression* arg2, Expression* arg3) +{ + return new Trinary_cond(arg1, arg2, arg3); +} + +// Max function. + +class Max_expression : public Binary_expression +{ + public: + Max_expression(Expression* left, Expression* right) + : Binary_expression(left, right) + { } + + uint64_t + value(const Expression_eval_info* eei) + { + Output_section* left_section; + uint64_t left_alignment; + uint64_t left = this->left_value(eei, &left_section, &left_alignment); + Output_section* right_section; + uint64_t right_alignment; + uint64_t right = this->right_value(eei, &right_section, &right_alignment); + if (left_section == right_section) + { + if (eei->result_section_pointer != NULL) + *eei->result_section_pointer = left_section; + } + else if ((left_section != NULL || right_section != NULL) + && parameters->options().relocatable()) + gold_warning(_("max applied to section relative value")); + if (eei->result_alignment_pointer != NULL) + { + uint64_t ra = *eei->result_alignment_pointer; + if (left > right) + ra = std::max(ra, left_alignment); + else if (right > left) + ra = std::max(ra, right_alignment); + else + ra = std::max(ra, std::max(left_alignment, right_alignment)); + *eei->result_alignment_pointer = ra; + } + return std::max(left, right); + } + + void + print(FILE* f) const + { this->print_function(f, "MAX"); } +}; + +extern "C" Expression* +script_exp_function_max(Expression* left, Expression* right) +{ + return new Max_expression(left, right); +} + +// Min function. + +class Min_expression : public Binary_expression +{ + public: + Min_expression(Expression* left, Expression* right) + : Binary_expression(left, right) + { } + + uint64_t + value(const Expression_eval_info* eei) + { + Output_section* left_section; + uint64_t left_alignment; + uint64_t left = this->left_value(eei, &left_section, &left_alignment); + Output_section* right_section; + uint64_t right_alignment; + uint64_t right = this->right_value(eei, &right_section, &right_alignment); + if (left_section == right_section) + { + if (eei->result_section_pointer != NULL) + *eei->result_section_pointer = left_section; + } + else if ((left_section != NULL || right_section != NULL) + && parameters->options().relocatable()) + gold_warning(_("min applied to section relative value")); + if (eei->result_alignment_pointer != NULL) + { + uint64_t ra = *eei->result_alignment_pointer; + if (left < right) + ra = std::max(ra, left_alignment); + else if (right < left) + ra = std::max(ra, right_alignment); + else + ra = std::max(ra, std::max(left_alignment, right_alignment)); + *eei->result_alignment_pointer = ra; + } + return std::min(left, right); + } + + void + print(FILE* f) const + { this->print_function(f, "MIN"); } +}; + +extern "C" Expression* +script_exp_function_min(Expression* left, Expression* right) +{ + return new Min_expression(left, right); +} + +// Class Section_expression. This is a parent class used for +// functions which take the name of an output section. + +class Section_expression : public Expression +{ + public: + Section_expression(const char* section_name, size_t section_name_len) + : section_name_(section_name, section_name_len) + { } + + uint64_t + value(const Expression_eval_info*); + + void + print(FILE* f) const + { fprintf(f, "%s(%s)", this->function_name(), this->section_name_.c_str()); } + + protected: + // The child class must implement this. + virtual uint64_t + value_from_output_section(const Expression_eval_info*, + Output_section*) = 0; + + // The child class must implement this. + virtual uint64_t + value_from_script_output_section(uint64_t address, uint64_t load_address, + uint64_t addralign, uint64_t size) = 0; + + // The child class must implement this. + virtual const char* + function_name() const = 0; + + private: + std::string section_name_; +}; + +uint64_t +Section_expression::value(const Expression_eval_info* eei) +{ + const char* section_name = this->section_name_.c_str(); + Output_section* os = eei->layout->find_output_section(section_name); + if (os != NULL) + return this->value_from_output_section(eei, os); + + uint64_t address; + uint64_t load_address; + uint64_t addralign; + uint64_t size; + const Script_options* ss = eei->layout->script_options(); + if (ss->saw_sections_clause()) + { + if (ss->script_sections()->get_output_section_info(section_name, + &address, + &load_address, + &addralign, + &size)) + return this->value_from_script_output_section(address, load_address, + addralign, size); + } + + gold_error("%s called on nonexistent output section '%s'", + this->function_name(), section_name); + return 0; +} + +// ABSOLUTE function. + +class Absolute_expression : public Unary_expression +{ + public: + Absolute_expression(Expression* arg) + : Unary_expression(arg) + { } + + uint64_t + value(const Expression_eval_info* eei) + { + uint64_t ret = this->arg_value(eei, NULL); + // Force the value to be absolute. + if (eei->result_section_pointer != NULL) + *eei->result_section_pointer = NULL; + return ret; + } + + void + print(FILE* f) const + { + fprintf(f, "ABSOLUTE("); + this->arg_print(f); + fprintf(f, ")"); + } +}; + +extern "C" Expression* +script_exp_function_absolute(Expression* arg) +{ + return new Absolute_expression(arg); +} + +// ALIGN function. + +class Align_expression : public Binary_expression +{ + public: + Align_expression(Expression* left, Expression* right) + : Binary_expression(left, right) + { } + + uint64_t + value(const Expression_eval_info* eei) + { + Output_section* align_section; + uint64_t align = this->right_value(eei, &align_section, NULL); + if (align_section != NULL + && parameters->options().relocatable()) + gold_warning(_("aligning to section relative value")); + + if (eei->result_alignment_pointer != NULL + && align > *eei->result_alignment_pointer) + { + uint64_t a = align; + while ((a & (a - 1)) != 0) + a &= a - 1; + *eei->result_alignment_pointer = a; + } + + uint64_t value = this->left_value(eei, eei->result_section_pointer, NULL); + if (align <= 1) + return value; + return ((value + align - 1) / align) * align; + } + + void + print(FILE* f) const + { this->print_function(f, "ALIGN"); } +}; + +extern "C" Expression* +script_exp_function_align(Expression* left, Expression* right) +{ + return new Align_expression(left, right); +} + +// ASSERT function. + +class Assert_expression : public Unary_expression +{ + public: + Assert_expression(Expression* arg, const char* message, size_t length) + : Unary_expression(arg), message_(message, length) + { } + + uint64_t + value(const Expression_eval_info* eei) + { + uint64_t value = this->arg_value(eei, eei->result_section_pointer); + if (!value && eei->check_assertions) + gold_error("%s", this->message_.c_str()); + return value; + } + + void + print(FILE* f) const + { + fprintf(f, "ASSERT("); + this->arg_print(f); + fprintf(f, ", %s)", this->message_.c_str()); + } + + private: + std::string message_; +}; + +extern "C" Expression* +script_exp_function_assert(Expression* expr, const char* message, + size_t length) +{ + return new Assert_expression(expr, message, length); +} + +// ADDR function. + +class Addr_expression : public Section_expression +{ + public: + Addr_expression(const char* section_name, size_t section_name_len) + : Section_expression(section_name, section_name_len) + { } + + protected: + uint64_t + value_from_output_section(const Expression_eval_info* eei, + Output_section* os) + { + if (eei->result_section_pointer != NULL) + *eei->result_section_pointer = os; + return os->address(); + } + + uint64_t + value_from_script_output_section(uint64_t address, uint64_t, uint64_t, + uint64_t) + { return address; } + + const char* + function_name() const + { return "ADDR"; } +}; + +extern "C" Expression* +script_exp_function_addr(const char* section_name, size_t section_name_len) +{ + return new Addr_expression(section_name, section_name_len); +} + +// ALIGNOF. + +class Alignof_expression : public Section_expression +{ + public: + Alignof_expression(const char* section_name, size_t section_name_len) + : Section_expression(section_name, section_name_len) + { } + + protected: + uint64_t + value_from_output_section(const Expression_eval_info*, + Output_section* os) + { return os->addralign(); } + + uint64_t + value_from_script_output_section(uint64_t, uint64_t, uint64_t addralign, + uint64_t) + { return addralign; } + + const char* + function_name() const + { return "ALIGNOF"; } +}; + +extern "C" Expression* +script_exp_function_alignof(const char* section_name, size_t section_name_len) +{ + return new Alignof_expression(section_name, section_name_len); +} + +// CONSTANT. It would be nice if we could simply evaluate this +// immediately and return an Integer_expression, but unfortunately we +// don't know the target. + +class Constant_expression : public Expression +{ + public: + Constant_expression(const char* name, size_t length); + + uint64_t + value(const Expression_eval_info*); + + void + print(FILE* f) const; + + private: + enum Constant_function + { + CONSTANT_MAXPAGESIZE, + CONSTANT_COMMONPAGESIZE + }; + + Constant_function function_; +}; + +Constant_expression::Constant_expression(const char* name, size_t length) +{ + if (length == 11 && strncmp(name, "MAXPAGESIZE", length) == 0) + this->function_ = CONSTANT_MAXPAGESIZE; + else if (length == 14 && strncmp(name, "COMMONPAGESIZE", length) == 0) + this->function_ = CONSTANT_COMMONPAGESIZE; + else + { + std::string s(name, length); + gold_error(_("unknown constant %s"), s.c_str()); + this->function_ = CONSTANT_MAXPAGESIZE; + } +} + +uint64_t +Constant_expression::value(const Expression_eval_info*) +{ + switch (this->function_) + { + case CONSTANT_MAXPAGESIZE: + return parameters->target().abi_pagesize(); + case CONSTANT_COMMONPAGESIZE: + return parameters->target().common_pagesize(); + default: + gold_unreachable(); + } +} + +void +Constant_expression::print(FILE* f) const +{ + const char* name; + switch (this->function_) + { + case CONSTANT_MAXPAGESIZE: + name = "MAXPAGESIZE"; + break; + case CONSTANT_COMMONPAGESIZE: + name = "COMMONPAGESIZE"; + break; + default: + gold_unreachable(); + } + fprintf(f, "CONSTANT(%s)", name); +} + +extern "C" Expression* +script_exp_function_constant(const char* name, size_t length) +{ + return new Constant_expression(name, length); +} + +// DATA_SEGMENT_ALIGN. FIXME: we don't implement this; we always fall +// back to the general case. + +extern "C" Expression* +script_exp_function_data_segment_align(Expression* left, Expression*) +{ + Expression* e1 = script_exp_function_align(script_exp_string(".", 1), left); + Expression* e2 = script_exp_binary_sub(left, script_exp_integer(1)); + Expression* e3 = script_exp_binary_bitwise_and(script_exp_string(".", 1), + e2); + return script_exp_binary_add(e1, e3); +} + +// DATA_SEGMENT_RELRO. FIXME: This is not implemented. + +extern "C" Expression* +script_exp_function_data_segment_relro_end(Expression*, Expression* right) +{ + return right; +} + +// DATA_SEGMENT_END. FIXME: This is not implemented. + +extern "C" Expression* +script_exp_function_data_segment_end(Expression* val) +{ + return val; +} + +// DEFINED function. + +class Defined_expression : public Expression +{ + public: + Defined_expression(const char* symbol_name, size_t symbol_name_len) + : symbol_name_(symbol_name, symbol_name_len) + { } + + uint64_t + value(const Expression_eval_info* eei) + { + Symbol* sym = eei->symtab->lookup(this->symbol_name_.c_str()); + return sym != NULL && sym->is_defined(); + } + + void + print(FILE* f) const + { fprintf(f, "DEFINED(%s)", this->symbol_name_.c_str()); } + + private: + std::string symbol_name_; +}; + +extern "C" Expression* +script_exp_function_defined(const char* symbol_name, size_t symbol_name_len) +{ + return new Defined_expression(symbol_name, symbol_name_len); +} + +// LOADADDR function + +class Loadaddr_expression : public Section_expression +{ + public: + Loadaddr_expression(const char* section_name, size_t section_name_len) + : Section_expression(section_name, section_name_len) + { } + + protected: + uint64_t + value_from_output_section(const Expression_eval_info* eei, + Output_section* os) + { + if (os->has_load_address()) + return os->load_address(); + else + { + if (eei->result_section_pointer != NULL) + *eei->result_section_pointer = os; + return os->address(); + } + } + + uint64_t + value_from_script_output_section(uint64_t, uint64_t load_address, uint64_t, + uint64_t) + { return load_address; } + + const char* + function_name() const + { return "LOADADDR"; } +}; + +extern "C" Expression* +script_exp_function_loadaddr(const char* section_name, size_t section_name_len) +{ + return new Loadaddr_expression(section_name, section_name_len); +} + +// SIZEOF function + +class Sizeof_expression : public Section_expression +{ + public: + Sizeof_expression(const char* section_name, size_t section_name_len) + : Section_expression(section_name, section_name_len) + { } + + protected: + uint64_t + value_from_output_section(const Expression_eval_info*, + Output_section* os) + { + // We can not use data_size here, as the size of the section may + // not have been finalized. Instead we get whatever the current + // size is. This will work correctly for backward references in + // linker scripts. + return os->current_data_size(); + } + + uint64_t + value_from_script_output_section(uint64_t, uint64_t, uint64_t, + uint64_t size) + { return size; } + + const char* + function_name() const + { return "SIZEOF"; } +}; + +extern "C" Expression* +script_exp_function_sizeof(const char* section_name, size_t section_name_len) +{ + return new Sizeof_expression(section_name, section_name_len); +} + +// SIZEOF_HEADERS. + +class Sizeof_headers_expression : public Expression +{ + public: + Sizeof_headers_expression() + { } + + uint64_t + value(const Expression_eval_info*); + + void + print(FILE* f) const + { fprintf(f, "SIZEOF_HEADERS"); } +}; + +uint64_t +Sizeof_headers_expression::value(const Expression_eval_info* eei) +{ + unsigned int ehdr_size; + unsigned int phdr_size; + if (parameters->target().get_size() == 32) + { + ehdr_size = elfcpp::Elf_sizes<32>::ehdr_size; + phdr_size = elfcpp::Elf_sizes<32>::phdr_size; + } + else if (parameters->target().get_size() == 64) + { + ehdr_size = elfcpp::Elf_sizes<64>::ehdr_size; + phdr_size = elfcpp::Elf_sizes<64>::phdr_size; + } + else + gold_unreachable(); + + return ehdr_size + phdr_size * eei->layout->expected_segment_count(); +} + +extern "C" Expression* +script_exp_function_sizeof_headers() +{ + return new Sizeof_headers_expression(); +} + +// SEGMENT_START. + +class Segment_start_expression : public Unary_expression +{ + public: + Segment_start_expression(const char* segment_name, size_t segment_name_len, + Expression* default_value) + : Unary_expression(default_value), + segment_name_(segment_name, segment_name_len) + { } + + uint64_t + value(const Expression_eval_info*); + + void + print(FILE* f) const + { + fprintf(f, "SEGMENT_START(\"%s\", ", this->segment_name_.c_str()); + this->arg_print(f); + fprintf(f, ")"); + } + + private: + std::string segment_name_; +}; + +uint64_t +Segment_start_expression::value(const Expression_eval_info* eei) +{ + // Check for command line overrides. + if (parameters->options().user_set_Ttext() + && this->segment_name_ == ".text") + return parameters->options().Ttext(); + else if (parameters->options().user_set_Tdata() + && this->segment_name_ == ".data") + return parameters->options().Tdata(); + else if (parameters->options().user_set_Tbss() + && this->segment_name_ == ".bss") + return parameters->options().Tbss(); + else + { + uint64_t ret = this->arg_value(eei, NULL); + // Force the value to be absolute. + if (eei->result_section_pointer != NULL) + *eei->result_section_pointer = NULL; + return ret; + } +} + +extern "C" Expression* +script_exp_function_segment_start(const char* segment_name, + size_t segment_name_len, + Expression* default_value) +{ + return new Segment_start_expression(segment_name, segment_name_len, + default_value); +} + +} // End namespace gold. diff --git a/binutils-2.25/gold/ffsll.c b/binutils-2.25/gold/ffsll.c new file mode 100644 index 00000000..b247bc30 --- /dev/null +++ b/binutils-2.25/gold/ffsll.c @@ -0,0 +1,48 @@ +/* ffsll.c -- version of ffsll for gold. */ + +/* Copyright 2009 Free Software Foundation, Inc. + Written by Ian Lance Taylor . + + 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 "config.h" + +#include + +extern int ffsll (long long); + +/* This file implements ffsll for systems which don't have it. We use + ffsll if possible because gcc supports it as a builtin which will + use a machine instruction if there is one. */ + +int +ffsll (long long arg) +{ + unsigned long long i; + int ret; + + if (arg == 0) + ret = 0; + else + { + ret = 1; + for (i = (unsigned long long) arg; (i & 1) == 0; i >>= 1) + ++ret; + } + return ret; +} diff --git a/binutils-2.25/gold/fileread.cc b/binutils-2.25/gold/fileread.cc new file mode 100644 index 00000000..743a1cd3 --- /dev/null +++ b/binutils-2.25/gold/fileread.cc @@ -0,0 +1,1140 @@ +// fileread.cc -- read files for gold + +// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012 +// Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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 +#include +#include +#include +#include + +#ifdef HAVE_SYS_MMAN_H +#include +#endif + +#ifdef HAVE_READV +#include +#endif + +#include +#include "filenames.h" + +#include "debug.h" +#include "parameters.h" +#include "options.h" +#include "dirsearch.h" +#include "target.h" +#include "binary.h" +#include "descriptors.h" +#include "gold-threads.h" +#include "fileread.h" + +// For systems without mmap support. +#ifndef HAVE_MMAP +# define mmap gold_mmap +# define munmap gold_munmap +# ifndef MAP_FAILED +# define MAP_FAILED (reinterpret_cast(-1)) +# endif +# ifndef PROT_READ +# define PROT_READ 0 +# endif +# ifndef MAP_PRIVATE +# define MAP_PRIVATE 0 +# endif + +# ifndef ENOSYS +# define ENOSYS EINVAL +# endif + +static void * +gold_mmap(void *, size_t, int, int, int, off_t) +{ + errno = ENOSYS; + return MAP_FAILED; +} + +static int +gold_munmap(void *, size_t) +{ + errno = ENOSYS; + return -1; +} + +#endif + +#ifndef HAVE_READV +struct iovec { void* iov_base; size_t iov_len; }; +ssize_t +readv(int, const iovec*, int) +{ + gold_unreachable(); +} +#endif + +namespace gold +{ + +// Get the last modified time of an unopened file. + +bool +get_mtime(const char* filename, Timespec* mtime) +{ + struct stat file_stat; + + if (stat(filename, &file_stat) < 0) + return false; +#ifdef HAVE_STAT_ST_MTIM + mtime->seconds = file_stat.st_mtim.tv_sec; + mtime->nanoseconds = file_stat.st_mtim.tv_nsec; +#else + mtime->seconds = file_stat.st_mtime; + mtime->nanoseconds = 0; +#endif + return true; +} + +// Class File_read. + +// A lock for the File_read static variables. +static Lock* file_counts_lock = NULL; +static Initialize_lock file_counts_initialize_lock(&file_counts_lock); + +// The File_read static variables. +unsigned long long File_read::total_mapped_bytes; +unsigned long long File_read::current_mapped_bytes; +unsigned long long File_read::maximum_mapped_bytes; + +// Class File_read::View. + +File_read::View::~View() +{ + gold_assert(!this->is_locked()); + switch (this->data_ownership_) + { + case DATA_ALLOCATED_ARRAY: + free(const_cast(this->data_)); + break; + case DATA_MMAPPED: + if (::munmap(const_cast(this->data_), this->size_) != 0) + gold_warning(_("munmap failed: %s"), strerror(errno)); + if (!parameters->options_valid() || parameters->options().stats()) + { + file_counts_initialize_lock.initialize(); + Hold_optional_lock hl(file_counts_lock); + File_read::current_mapped_bytes -= this->size_; + } + break; + case DATA_NOT_OWNED: + break; + default: + gold_unreachable(); + } +} + +void +File_read::View::lock() +{ + ++this->lock_count_; +} + +void +File_read::View::unlock() +{ + gold_assert(this->lock_count_ > 0); + --this->lock_count_; +} + +bool +File_read::View::is_locked() +{ + return this->lock_count_ > 0; +} + +// Class File_read. + +File_read::~File_read() +{ + gold_assert(this->token_.is_writable()); + if (this->is_descriptor_opened_) + { + release_descriptor(this->descriptor_, true); + this->descriptor_ = -1; + this->is_descriptor_opened_ = false; + } + this->name_.clear(); + this->clear_views(CLEAR_VIEWS_ALL); +} + +// Open the file. + +bool +File_read::open(const Task* task, const std::string& name) +{ + gold_assert(this->token_.is_writable() + && this->descriptor_ < 0 + && !this->is_descriptor_opened_ + && this->name_.empty()); + this->name_ = name; + + this->descriptor_ = open_descriptor(-1, this->name_.c_str(), + O_RDONLY); + + if (this->descriptor_ >= 0) + { + this->is_descriptor_opened_ = true; + struct stat s; + if (::fstat(this->descriptor_, &s) < 0) + gold_error(_("%s: fstat failed: %s"), + this->name_.c_str(), strerror(errno)); + this->size_ = s.st_size; + gold_debug(DEBUG_FILES, "Attempt to open %s succeeded", + this->name_.c_str()); + this->token_.add_writer(task); + } + + return this->descriptor_ >= 0; +} + +// Open the file with the contents in memory. + +bool +File_read::open(const Task* task, const std::string& name, + const unsigned char* contents, off_t size) +{ + gold_assert(this->token_.is_writable() + && this->descriptor_ < 0 + && !this->is_descriptor_opened_ + && this->name_.empty()); + this->name_ = name; + this->whole_file_view_ = new View(0, size, contents, 0, false, + View::DATA_NOT_OWNED); + this->add_view(this->whole_file_view_); + this->size_ = size; + this->token_.add_writer(task); + return true; +} + +// Reopen a descriptor if necessary. + +void +File_read::reopen_descriptor() +{ + if (!this->is_descriptor_opened_) + { + this->descriptor_ = open_descriptor(this->descriptor_, + this->name_.c_str(), + O_RDONLY); + if (this->descriptor_ < 0) + gold_fatal(_("could not reopen file %s"), this->name_.c_str()); + this->is_descriptor_opened_ = true; + } +} + +// Release the file. This is called when we are done with the file in +// a Task. + +void +File_read::release() +{ + gold_assert(this->is_locked()); + + if (!parameters->options_valid() || parameters->options().stats()) + { + file_counts_initialize_lock.initialize(); + Hold_optional_lock hl(file_counts_lock); + File_read::total_mapped_bytes += this->mapped_bytes_; + File_read::current_mapped_bytes += this->mapped_bytes_; + if (File_read::current_mapped_bytes > File_read::maximum_mapped_bytes) + File_read::maximum_mapped_bytes = File_read::current_mapped_bytes; + } + + this->mapped_bytes_ = 0; + + // Only clear views if there is only one attached object. Otherwise + // we waste time trying to clear cached archive views. Similarly + // for releasing the descriptor. + if (this->object_count_ <= 1) + { + this->clear_views(CLEAR_VIEWS_NORMAL); + if (this->is_descriptor_opened_) + { + release_descriptor(this->descriptor_, false); + this->is_descriptor_opened_ = false; + } + } + + this->released_ = true; +} + +// Lock the file. + +void +File_read::lock(const Task* task) +{ + gold_assert(this->released_); + this->token_.add_writer(task); + this->released_ = false; +} + +// Unlock the file. + +void +File_read::unlock(const Task* task) +{ + this->release(); + this->token_.remove_writer(task); +} + +// Return whether the file is locked. + +bool +File_read::is_locked() const +{ + if (!this->token_.is_writable()) + return true; + // The file is not locked, so it should have been released. + gold_assert(this->released_); + return false; +} + +// See if we have a view which covers the file starting at START for +// SIZE bytes. Return a pointer to the View if found, NULL if not. +// If BYTESHIFT is not -1U, the returned View must have the specified +// byte shift; otherwise, it may have any byte shift. If VSHIFTED is +// not NULL, this sets *VSHIFTED to a view which would have worked if +// not for the requested BYTESHIFT. + +inline File_read::View* +File_read::find_view(off_t start, section_size_type size, + unsigned int byteshift, File_read::View** vshifted) const +{ + gold_assert(start <= this->size_ + && (static_cast(size) + <= static_cast(this->size_ - start))); + + if (vshifted != NULL) + *vshifted = NULL; + + // If we have the whole file mmapped, and the alignment is right, + // we can return it. + if (this->whole_file_view_) + if (byteshift == -1U || byteshift == 0) + return this->whole_file_view_; + + off_t page = File_read::page_offset(start); + + unsigned int bszero = 0; + Views::const_iterator p = this->views_.upper_bound(std::make_pair(page - 1, + bszero)); + + while (p != this->views_.end() && p->first.first <= page) + { + if (p->second->start() <= start + && (p->second->start() + static_cast(p->second->size()) + >= start + static_cast(size))) + { + if (byteshift == -1U || byteshift == p->second->byteshift()) + { + p->second->set_accessed(); + return p->second; + } + + if (vshifted != NULL && *vshifted == NULL) + *vshifted = p->second; + } + + ++p; + } + + return NULL; +} + +// Read SIZE bytes from the file starting at offset START. Read into +// the buffer at P. + +void +File_read::do_read(off_t start, section_size_type size, void* p) +{ + ssize_t bytes; + if (this->whole_file_view_ != NULL) + { + bytes = this->size_ - start; + if (static_cast(bytes) >= size) + { + memcpy(p, this->whole_file_view_->data() + start, size); + return; + } + } + else + { + this->reopen_descriptor(); + + char *read_ptr = static_cast(p); + off_t read_pos = start; + size_t to_read = size; + do + { + bytes = ::pread(this->descriptor_, read_ptr, to_read, read_pos); + if (bytes < 0) + gold_fatal(_("%s: pread failed: %s"), + this->filename().c_str(), strerror(errno)); + + read_pos += bytes; + read_ptr += bytes; + to_read -= bytes; + if (to_read == 0) + return; + } + while (bytes > 0); + + bytes = size - to_read; + } + + gold_fatal(_("%s: file too short: read only %lld of %lld bytes at %lld"), + this->filename().c_str(), + static_cast(bytes), + static_cast(size), + static_cast(start)); +} + +// Read data from the file. + +void +File_read::read(off_t start, section_size_type size, void* p) +{ + const File_read::View* pv = this->find_view(start, size, -1U, NULL); + if (pv != NULL) + { + memcpy(p, pv->data() + (start - pv->start() + pv->byteshift()), size); + return; + } + + this->do_read(start, size, p); +} + +// Add a new view. There may already be an existing view at this +// offset. If there is, the new view will be larger, and should +// replace the old view. + +void +File_read::add_view(File_read::View* v) +{ + std::pair ins = + this->views_.insert(std::make_pair(std::make_pair(v->start(), + v->byteshift()), + v)); + if (ins.second) + return; + + // There was an existing view at this offset. It must not be large + // enough. We can't delete it here, since something might be using + // it; we put it on a list to be deleted when the file is unlocked. + File_read::View* vold = ins.first->second; + gold_assert(vold->size() < v->size()); + if (vold->should_cache()) + { + v->set_cache(); + vold->clear_cache(); + } + this->saved_views_.push_back(vold); + + ins.first->second = v; +} + +// Make a new view with a specified byteshift, reading the data from +// the file. + +File_read::View* +File_read::make_view(off_t start, section_size_type size, + unsigned int byteshift, bool cache) +{ + gold_assert(size > 0); + gold_assert(start <= this->size_ + && (static_cast(size) + <= static_cast(this->size_ - start))); + + off_t poff = File_read::page_offset(start); + + section_size_type psize = File_read::pages(size + (start - poff)); + + if (poff + static_cast(psize) >= this->size_) + { + psize = this->size_ - poff; + gold_assert(psize >= size); + } + + void* p; + View::Data_ownership ownership; + if (byteshift != 0) + { + p = malloc(psize + byteshift); + if (p == NULL) + gold_nomem(); + memset(p, 0, byteshift); + this->do_read(poff, psize, static_cast(p) + byteshift); + ownership = View::DATA_ALLOCATED_ARRAY; + } + else + { + this->reopen_descriptor(); + p = ::mmap(NULL, psize, PROT_READ, MAP_PRIVATE, this->descriptor_, poff); + if (p != MAP_FAILED) + { + ownership = View::DATA_MMAPPED; + this->mapped_bytes_ += psize; + } + else + { + p = malloc(psize); + if (p == NULL) + gold_nomem(); + this->do_read(poff, psize, p); + ownership = View::DATA_ALLOCATED_ARRAY; + } + } + + const unsigned char* pbytes = static_cast(p); + File_read::View* v = new File_read::View(poff, psize, pbytes, byteshift, + cache, ownership); + + this->add_view(v); + + return v; +} + +// Find a View or make a new one, shifted as required by the file +// offset OFFSET and ALIGNED. + +File_read::View* +File_read::find_or_make_view(off_t offset, off_t start, + section_size_type size, bool aligned, bool cache) +{ + // Check that start and end of the view are within the file. + if (start > this->size_ + || (static_cast(size) + > static_cast(this->size_ - start))) + gold_fatal(_("%s: attempt to map %lld bytes at offset %lld exceeds " + "size of file; the file may be corrupt"), + this->filename().c_str(), + static_cast(size), + static_cast(start)); + + unsigned int byteshift; + if (offset == 0) + byteshift = 0; + else + { + unsigned int target_size = (!parameters->target_valid() + ? 64 + : parameters->target().get_size()); + byteshift = offset & ((target_size / 8) - 1); + + // Set BYTESHIFT to the number of dummy bytes which must be + // inserted before the data in order for this data to be + // aligned. + if (byteshift != 0) + byteshift = (target_size / 8) - byteshift; + } + + // If --map-whole-files is set, make sure we have a + // whole file view. Options may not yet be ready, e.g., + // when reading a version script. We then default to + // --no-map-whole-files. + if (this->whole_file_view_ == NULL + && parameters->options_valid() + && parameters->options().map_whole_files()) + this->whole_file_view_ = this->make_view(0, this->size_, 0, cache); + + // Try to find a View with the required BYTESHIFT. + File_read::View* vshifted; + File_read::View* v = this->find_view(offset + start, size, + aligned ? byteshift : -1U, + &vshifted); + if (v != NULL) + { + if (cache) + v->set_cache(); + return v; + } + + // If VSHIFTED is not NULL, then it has the data we need, but with + // the wrong byteshift. + v = vshifted; + if (v != NULL) + { + gold_assert(aligned); + + unsigned char* pbytes; + pbytes = static_cast(malloc(v->size() + byteshift)); + if (pbytes == NULL) + gold_nomem(); + memset(pbytes, 0, byteshift); + memcpy(pbytes + byteshift, v->data() + v->byteshift(), v->size()); + + File_read::View* shifted_view = + new File_read::View(v->start(), v->size(), pbytes, byteshift, + cache, View::DATA_ALLOCATED_ARRAY); + + this->add_view(shifted_view); + return shifted_view; + } + + // Make a new view. If we don't need an aligned view, use a + // byteshift of 0, so that we can use mmap. + return this->make_view(offset + start, size, + aligned ? byteshift : 0, + cache); +} + +// Get a view into the file. + +const unsigned char* +File_read::get_view(off_t offset, off_t start, section_size_type size, + bool aligned, bool cache) +{ + File_read::View* pv = this->find_or_make_view(offset, start, size, + aligned, cache); + return pv->data() + (offset + start - pv->start() + pv->byteshift()); +} + +File_view* +File_read::get_lasting_view(off_t offset, off_t start, section_size_type size, + bool aligned, bool cache) +{ + File_read::View* pv = this->find_or_make_view(offset, start, size, + aligned, cache); + pv->lock(); + return new File_view(*this, pv, + (pv->data() + + (offset + start - pv->start() + pv->byteshift()))); +} + +// Use readv to read COUNT entries from RM starting at START. BASE +// must be added to all file offsets in RM. + +void +File_read::do_readv(off_t base, const Read_multiple& rm, size_t start, + size_t count) +{ + unsigned char discard[File_read::page_size]; + iovec iov[File_read::max_readv_entries * 2]; + size_t iov_index = 0; + + off_t first_offset = rm[start].file_offset; + off_t last_offset = first_offset; + ssize_t want = 0; + for (size_t i = 0; i < count; ++i) + { + const Read_multiple_entry& i_entry(rm[start + i]); + + if (i_entry.file_offset > last_offset) + { + size_t skip = i_entry.file_offset - last_offset; + gold_assert(skip <= sizeof discard); + + iov[iov_index].iov_base = discard; + iov[iov_index].iov_len = skip; + ++iov_index; + + want += skip; + } + + iov[iov_index].iov_base = i_entry.buffer; + iov[iov_index].iov_len = i_entry.size; + ++iov_index; + + want += i_entry.size; + + last_offset = i_entry.file_offset + i_entry.size; + } + + this->reopen_descriptor(); + + gold_assert(iov_index < sizeof iov / sizeof iov[0]); + + if (::lseek(this->descriptor_, base + first_offset, SEEK_SET) < 0) + gold_fatal(_("%s: lseek failed: %s"), + this->filename().c_str(), strerror(errno)); + + ssize_t got = ::readv(this->descriptor_, iov, iov_index); + + if (got < 0) + gold_fatal(_("%s: readv failed: %s"), + this->filename().c_str(), strerror(errno)); + if (got != want) + gold_fatal(_("%s: file too short: read only %zd of %zd bytes at %lld"), + this->filename().c_str(), + got, want, static_cast(base + first_offset)); +} + +// Portable IOV_MAX. + +#if !defined(HAVE_READV) +#define GOLD_IOV_MAX 1 +#elif defined(IOV_MAX) +#define GOLD_IOV_MAX IOV_MAX +#else +#define GOLD_IOV_MAX (File_read::max_readv_entries * 2) +#endif + +// Read several pieces of data from the file. + +void +File_read::read_multiple(off_t base, const Read_multiple& rm) +{ + static size_t iov_max = GOLD_IOV_MAX; + size_t count = rm.size(); + size_t i = 0; + while (i < count) + { + // Find up to MAX_READV_ENTRIES consecutive entries which are + // less than one page apart. + const Read_multiple_entry& i_entry(rm[i]); + off_t i_off = i_entry.file_offset; + off_t end_off = i_off + i_entry.size; + size_t j; + for (j = i + 1; j < count; ++j) + { + if (j - i >= File_read::max_readv_entries || j - i >= iov_max / 2) + break; + const Read_multiple_entry& j_entry(rm[j]); + off_t j_off = j_entry.file_offset; + gold_assert(j_off >= end_off); + off_t j_end_off = j_off + j_entry.size; + if (j_end_off - end_off >= File_read::page_size) + break; + end_off = j_end_off; + } + + if (j == i + 1) + this->read(base + i_off, i_entry.size, i_entry.buffer); + else + { + File_read::View* view = this->find_view(base + i_off, + end_off - i_off, + -1U, NULL); + if (view == NULL) + this->do_readv(base, rm, i, j - i); + else + { + const unsigned char* v = (view->data() + + (base + i_off - view->start() + + view->byteshift())); + for (size_t k = i; k < j; ++k) + { + const Read_multiple_entry& k_entry(rm[k]); + gold_assert((convert_to_section_size_type(k_entry.file_offset + - i_off) + + k_entry.size) + <= convert_to_section_size_type(end_off + - i_off)); + memcpy(k_entry.buffer, + v + (k_entry.file_offset - i_off), + k_entry.size); + } + } + } + + i = j; + } +} + +// Mark all views as no longer cached. + +void +File_read::clear_view_cache_marks() +{ + // Just ignore this if there are multiple objects associated with + // the file. Otherwise we will wind up uncaching and freeing some + // views for other objects. + if (this->object_count_ > 1) + return; + + for (Views::iterator p = this->views_.begin(); + p != this->views_.end(); + ++p) + p->second->clear_cache(); + for (Saved_views::iterator p = this->saved_views_.begin(); + p != this->saved_views_.end(); + ++p) + (*p)->clear_cache(); +} + +// Remove all the file views. For a file which has multiple +// associated objects (i.e., an archive), we keep accessed views +// around until next time, in the hopes that they will be useful for +// the next object. + +void +File_read::clear_views(Clear_views_mode mode) +{ + bool keep_files_mapped = (parameters->options_valid() + && parameters->options().keep_files_mapped()); + Views::iterator p = this->views_.begin(); + while (p != this->views_.end()) + { + bool should_delete; + if (p->second->is_locked() || p->second->is_permanent_view()) + should_delete = false; + else if (mode == CLEAR_VIEWS_ALL) + should_delete = true; + else if ((p->second->should_cache() + || p->second == this->whole_file_view_) + && keep_files_mapped) + should_delete = false; + else if (this->object_count_ > 1 + && p->second->accessed() + && mode != CLEAR_VIEWS_ARCHIVE) + should_delete = false; + else + should_delete = true; + + if (should_delete) + { + if (p->second == this->whole_file_view_) + this->whole_file_view_ = NULL; + delete p->second; + + // map::erase invalidates only the iterator to the deleted + // element. + Views::iterator pe = p; + ++p; + this->views_.erase(pe); + } + else + { + p->second->clear_accessed(); + ++p; + } + } + + Saved_views::iterator q = this->saved_views_.begin(); + while (q != this->saved_views_.end()) + { + if (!(*q)->is_locked()) + { + delete *q; + q = this->saved_views_.erase(q); + } + else + { + gold_assert(mode != CLEAR_VIEWS_ALL); + ++q; + } + } +} + +// Print statistical information to stderr. This is used for --stats. + +void +File_read::print_stats() +{ + fprintf(stderr, _("%s: total bytes mapped for read: %llu\n"), + program_name, File_read::total_mapped_bytes); + fprintf(stderr, _("%s: maximum bytes mapped for read at one time: %llu\n"), + program_name, File_read::maximum_mapped_bytes); +} + +// Class File_view. + +File_view::~File_view() +{ + gold_assert(this->file_.is_locked()); + this->view_->unlock(); +} + +// Class Input_file. + +// Create a file given just the filename. + +Input_file::Input_file(const char* name) + : found_name_(), file_(), is_in_sysroot_(false), format_(FORMAT_NONE) +{ + this->input_argument_ = + new Input_file_argument(name, Input_file_argument::INPUT_FILE_TYPE_FILE, + "", false, Position_dependent_options()); +} + +// Create a file for testing. + +Input_file::Input_file(const Task* task, const char* name, + const unsigned char* contents, off_t size) + : file_() +{ + this->input_argument_ = + new Input_file_argument(name, Input_file_argument::INPUT_FILE_TYPE_FILE, + "", false, Position_dependent_options()); + bool ok = this->file_.open(task, name, contents, size); + gold_assert(ok); +} + +// Return the position dependent options in force for this file. + +const Position_dependent_options& +Input_file::options() const +{ + return this->input_argument_->options(); +} + +// Return the name given by the user. For -lc this will return "c". + +const char* +Input_file::name() const +{ + return this->input_argument_->name(); +} + +// Return whether this file is in a system directory. + +bool +Input_file::is_in_system_directory() const +{ + if (this->is_in_sysroot()) + return true; + return parameters->options().is_in_system_directory(this->filename()); +} + +// Return whether we are only reading symbols. + +bool +Input_file::just_symbols() const +{ + return this->input_argument_->just_symbols(); +} + +// Return whether this is a file that we will search for in the list +// of directories. + +bool +Input_file::will_search_for() const +{ + return (!IS_ABSOLUTE_PATH(this->input_argument_->name()) + && (this->input_argument_->is_lib() + || this->input_argument_->is_searched_file() + || this->input_argument_->extra_search_path() != NULL)); +} + +// Return the file last modification time. Calls gold_fatal if the stat +// system call failed. + +Timespec +File_read::get_mtime() +{ + struct stat file_stat; + this->reopen_descriptor(); + + if (fstat(this->descriptor_, &file_stat) < 0) + gold_fatal(_("%s: stat failed: %s"), this->name_.c_str(), + strerror(errno)); +#ifdef HAVE_STAT_ST_MTIM + return Timespec(file_stat.st_mtim.tv_sec, file_stat.st_mtim.tv_nsec); +#else + return Timespec(file_stat.st_mtime, 0); +#endif +} + +// Try to find a file in the extra search dirs. Returns true on success. + +bool +Input_file::try_extra_search_path(int* pindex, + const Input_file_argument* input_argument, + std::string filename, std::string* found_name, + std::string* namep) +{ + if (input_argument->extra_search_path() == NULL) + return false; + + std::string name = input_argument->extra_search_path(); + if (!IS_DIR_SEPARATOR(name[name.length() - 1])) + name += '/'; + name += filename; + + struct stat dummy_stat; + if (*pindex > 0 || ::stat(name.c_str(), &dummy_stat) < 0) + return false; + + *found_name = filename; + *namep = name; + return true; +} + +// Find the actual file. +// If the filename is not absolute, we assume it is in the current +// directory *except* when: +// A) input_argument_->is_lib() is true; +// B) input_argument_->is_searched_file() is true; or +// C) input_argument_->extra_search_path() is not empty. +// In each, we look in extra_search_path + library_path to find +// the file location, rather than the current directory. + +bool +Input_file::find_file(const Dirsearch& dirpath, int* pindex, + const Input_file_argument* input_argument, + bool* is_in_sysroot, + std::string* found_name, std::string* namep) +{ + std::string name; + + // Case 1: name is an absolute file, just try to open it + // Case 2: name is relative but is_lib is false, is_searched_file is false, + // and extra_search_path is empty + if (IS_ABSOLUTE_PATH(input_argument->name()) + || (!input_argument->is_lib() + && !input_argument->is_searched_file() + && input_argument->extra_search_path() == NULL)) + { + name = input_argument->name(); + *found_name = name; + *namep = name; + return true; + } + // Case 3: is_lib is true or is_searched_file is true + else if (input_argument->is_lib() + || input_argument->is_searched_file()) + { + std::vector names; + names.reserve(2); + if (input_argument->is_lib()) + { + std::string prefix = "lib"; + prefix += input_argument->name(); + if (parameters->options().is_static() + || !input_argument->options().Bdynamic()) + names.push_back(prefix + ".a"); + else + { + names.push_back(prefix + ".so"); + names.push_back(prefix + ".a"); + } + } + else + names.push_back(input_argument->name()); + + for (std::vector::const_iterator n = names.begin(); + n != names.end(); + ++n) + if (Input_file::try_extra_search_path(pindex, input_argument, *n, + found_name, namep)) + return true; + + // It is not in the extra_search_path. + name = dirpath.find(names, is_in_sysroot, pindex, found_name); + if (name.empty()) + { + gold_error(_("cannot find %s%s"), + input_argument->is_lib() ? "-l" : "", + input_argument->name()); + return false; + } + *namep = name; + return true; + } + // Case 4: extra_search_path is not empty + else + { + gold_assert(input_argument->extra_search_path() != NULL); + + if (try_extra_search_path(pindex, input_argument, input_argument->name(), + found_name, namep)) + return true; + + // extra_search_path failed, so check the normal search-path. + int index = *pindex; + if (index > 0) + --index; + name = dirpath.find(std::vector(1, input_argument->name()), + is_in_sysroot, &index, found_name); + if (name.empty()) + { + gold_error(_("cannot find %s"), + input_argument->name()); + return false; + } + *namep = name; + *pindex = index + 1; + return true; + } +} + +// Open the file. + +bool +Input_file::open(const Dirsearch& dirpath, const Task* task, int* pindex) +{ + std::string name; + if (!Input_file::find_file(dirpath, pindex, this->input_argument_, + &this->is_in_sysroot_, &this->found_name_, &name)) + return false; + + // Now that we've figured out where the file lives, try to open it. + + General_options::Object_format format = + this->input_argument_->options().format_enum(); + bool ok; + if (format == General_options::OBJECT_FORMAT_ELF) + { + ok = this->file_.open(task, name); + this->format_ = FORMAT_ELF; + } + else + { + gold_assert(format == General_options::OBJECT_FORMAT_BINARY); + ok = this->open_binary(task, name); + this->format_ = FORMAT_BINARY; + } + + if (!ok) + { + gold_error(_("cannot open %s: %s"), + name.c_str(), strerror(errno)); + this->format_ = FORMAT_NONE; + return false; + } + + return true; +} + +// Open a file for --format binary. + +bool +Input_file::open_binary(const Task* task, const std::string& name) +{ + // In order to open a binary file, we need machine code, size, and + // endianness. We may not have a valid target at this point, in + // which case we use the default target. + parameters_force_valid_target(); + const Target& target(parameters->target()); + + Binary_to_elf binary_to_elf(target.machine_code(), + target.get_size(), + target.is_big_endian(), + name); + if (!binary_to_elf.convert(task)) + return false; + return this->file_.open(task, name, binary_to_elf.converted_data_leak(), + binary_to_elf.converted_size()); +} + +} // End namespace gold. diff --git a/binutils-2.25/gold/fileread.h b/binutils-2.25/gold/fileread.h new file mode 100644 index 00000000..74aeec94 --- /dev/null +++ b/binutils-2.25/gold/fileread.h @@ -0,0 +1,611 @@ +// fileread.h -- read files for gold -*- C++ -*- + +// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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. + +// Classes used to read data from binary input files. + +#ifndef GOLD_FILEREAD_H +#define GOLD_FILEREAD_H + +#include +#include +#include +#include + +#include "token.h" + +namespace gold +{ + +// Since not all system supports stat.st_mtim and struct timespec, +// we define our own structure and fill the nanoseconds if we can. + +struct Timespec +{ + Timespec() + : seconds(0), nanoseconds(0) + { } + + Timespec(time_t a_seconds, int a_nanoseconds) + : seconds(a_seconds), nanoseconds(a_nanoseconds) + { } + + time_t seconds; + int nanoseconds; +}; + +// Get the last modified time of an unopened file. Returns false if the +// file does not exist. + +bool +get_mtime(const char* filename, Timespec* mtime); + +class Position_dependent_options; +class Input_file_argument; +class Dirsearch; +class File_view; + +// File_read manages a file descriptor and mappings for a file we are +// reading. + +class File_read +{ + public: + File_read() + : name_(), descriptor_(-1), is_descriptor_opened_(false), object_count_(0), + size_(0), token_(false), views_(), saved_views_(), mapped_bytes_(0), + released_(true), whole_file_view_(NULL) + { } + + ~File_read(); + + // Open a file. + bool + open(const Task*, const std::string& name); + + // Pretend to open the file, but provide the file contents. No + // actual file system activity will occur. This is used for + // testing. + bool + open(const Task*, const std::string& name, const unsigned char* contents, + off_t size); + + // Return the file name. + const std::string& + filename() const + { return this->name_; } + + // Add an object associated with a file. + void + add_object() + { ++this->object_count_; } + + // Remove an object associated with a file. + void + remove_object() + { --this->object_count_; } + + // Lock the file for exclusive access within a particular Task::run + // execution. This routine may only be called when the workqueue + // lock is held. + void + lock(const Task* t); + + // Unlock the file. + void + unlock(const Task* t); + + // Test whether the object is locked. + bool + is_locked() const; + + // Return the token, so that the task can be queued. + Task_token* + token() + { return &this->token_; } + + // Release the file. This indicates that we aren't going to do + // anything further with it until it is unlocked. This is used + // because a Task which locks the file never calls either lock or + // unlock; it just locks the token. The basic rule is that a Task + // which locks a file via the Task::locks interface must explicitly + // call release() when it is done. This is not necessary for code + // which calls unlock() on the file. + void + release(); + + // Return the size of the file. + off_t + filesize() const + { return this->size_; } + + // Return a view into the file starting at file offset START for + // SIZE bytes. OFFSET is the offset into the input file for the + // file we are reading; this is zero for a normal object file, + // non-zero for an object file in an archive. ALIGNED is true if + // the data must be naturally aligned (i.e., aligned to the size + // of a target word); this only matters when OFFSET is not zero. + // The pointer will remain valid until the File_read is unlocked. + // It is an error if we can not read enough data from the file. + // The CACHE parameter is a hint as to whether it will be useful + // to cache this data for later accesses--i.e., later calls to + // get_view, read, or get_lasting_view which retrieve the same + // data. + const unsigned char* + get_view(off_t offset, off_t start, section_size_type size, bool aligned, + bool cache); + + // Read data from the file into the buffer P starting at file offset + // START for SIZE bytes. + void + read(off_t start, section_size_type size, void* p); + + // Return a lasting view into the file starting at file offset START + // for SIZE bytes. This is allocated with new, and the caller is + // responsible for deleting it when done. The data associated with + // this view will remain valid until the view is deleted. It is an + // error if we can not read enough data from the file. The OFFSET, + // ALIGNED and CACHE parameters are as in get_view. + File_view* + get_lasting_view(off_t offset, off_t start, section_size_type size, + bool aligned, bool cache); + + // Mark all views as no longer cached. + void + clear_view_cache_marks(); + + // Discard all uncached views. This is normally done by release(), + // but not for objects in archives. FIXME: This is a complicated + // interface, and it would be nice to have something more automatic. + void + clear_uncached_views() + { this->clear_views(CLEAR_VIEWS_ARCHIVE); } + + // A struct used to do a multiple read. + struct Read_multiple_entry + { + // The file offset of the data to read. + off_t file_offset; + // The amount of data to read. + section_size_type size; + // The buffer where the data should be placed. + unsigned char* buffer; + + Read_multiple_entry(off_t o, section_size_type s, unsigned char* b) + : file_offset(o), size(s), buffer(b) + { } + }; + + typedef std::vector Read_multiple; + + // Read a bunch of data from the file into various different + // locations. The vector must be sorted by ascending file_offset. + // BASE is a base offset to be added to all the offsets in the + // vector. + void + read_multiple(off_t base, const Read_multiple&); + + // Dump statistical information to stderr. + static void + print_stats(); + + // Return the open file descriptor (for plugins). + int + descriptor() + { + this->reopen_descriptor(); + return this->descriptor_; + } + + // Return the file last modification time. Calls gold_fatal if the stat + // system call failed. + Timespec + get_mtime(); + + private: + // Control for what views to clear. + enum Clear_views_mode + { + // Clear uncached views not used by an archive. + CLEAR_VIEWS_NORMAL, + // Clear all uncached views (including in an archive). + CLEAR_VIEWS_ARCHIVE, + // Clear all views (i.e., we're destroying the file). + CLEAR_VIEWS_ALL + }; + + // This class may not be copied. + File_read(const File_read&); + File_read& operator=(const File_read&); + + // Total bytes mapped into memory during the link if --stats. + static unsigned long long total_mapped_bytes; + + // Current number of bytes mapped into memory during the link if + // --stats. + static unsigned long long current_mapped_bytes; + + // High water mark of bytes mapped into memory during the link if + // --stats. + static unsigned long long maximum_mapped_bytes; + + // A view into the file. + class View + { + public: + // Specifies how to dispose the data on destruction of the view. + enum Data_ownership + { + // Data owned by File object - nothing done in destructor. + DATA_NOT_OWNED, + // Data allocated with new[] and owned by this object - should + // use delete[]. + DATA_ALLOCATED_ARRAY, + // Data mmapped and owned by this object - should munmap. + DATA_MMAPPED + }; + + View(off_t start, section_size_type size, const unsigned char* data, + unsigned int byteshift, bool cache, Data_ownership data_ownership) + : start_(start), size_(size), data_(data), lock_count_(0), + byteshift_(byteshift), cache_(cache), data_ownership_(data_ownership), + accessed_(true) + { } + + ~View(); + + off_t + start() const + { return this->start_; } + + section_size_type + size() const + { return this->size_; } + + const unsigned char* + data() const + { return this->data_; } + + void + lock(); + + void + unlock(); + + bool + is_locked(); + + unsigned int + byteshift() const + { return this->byteshift_; } + + void + set_cache() + { this->cache_ = true; } + + void + clear_cache() + { this->cache_ = false; } + + bool + should_cache() const + { return this->cache_; } + + void + set_accessed() + { this->accessed_ = true; } + + void + clear_accessed() + { this->accessed_= false; } + + bool + accessed() const + { return this->accessed_; } + + // Returns TRUE if this view contains permanent data -- e.g., data that + // was supplied by the owner of the File object. + bool + is_permanent_view() const + { return this->data_ownership_ == DATA_NOT_OWNED; } + + private: + View(const View&); + View& operator=(const View&); + + // The file offset of the start of the view. + off_t start_; + // The size of the view. + section_size_type size_; + // A pointer to the actual bytes. + const unsigned char* data_; + // The number of locks on this view. + int lock_count_; + // The number of bytes that the view is shifted relative to the + // underlying file. This is used to align data. This is normally + // zero, except possibly for an object in an archive. + unsigned int byteshift_; + // Whether the view is cached. + bool cache_; + // Whether the view is mapped into memory. If not, data_ points + // to memory allocated using new[]. + Data_ownership data_ownership_; + // Whether the view has been accessed recently. + bool accessed_; + }; + + friend class View; + friend class File_view; + + // The type of a mapping from page start and byte shift to views. + typedef std::map, View*> Views; + + // A simple list of Views. + typedef std::list Saved_views; + + // Open the descriptor if necessary. + void + reopen_descriptor(); + + // Find a view into the file. + View* + find_view(off_t start, section_size_type size, unsigned int byteshift, + View** vshifted) const; + + // Read data from the file into a buffer. + void + do_read(off_t start, section_size_type size, void* p); + + // Add a view. + void + add_view(View*); + + // Make a view into the file. + View* + make_view(off_t start, section_size_type size, unsigned int byteshift, + bool cache); + + // Find or make a view into the file. + View* + find_or_make_view(off_t offset, off_t start, section_size_type size, + bool aligned, bool cache); + + // Clear the file views. + void + clear_views(Clear_views_mode); + + // The size of a file page for buffering data. + static const off_t page_size = 8192; + + // Given a file offset, return the page offset. + static off_t + page_offset(off_t file_offset) + { return file_offset & ~ (page_size - 1); } + + // Given a file size, return the size to read integral pages. + static off_t + pages(off_t file_size) + { return (file_size + (page_size - 1)) & ~ (page_size - 1); } + + // The maximum number of entries we will pass to ::readv. + static const size_t max_readv_entries = 128; + + // Use readv to read data. + void + do_readv(off_t base, const Read_multiple&, size_t start, size_t count); + + // File name. + std::string name_; + // File descriptor. + int descriptor_; + // Whether we have regained the descriptor after releasing the file. + bool is_descriptor_opened_; + // The number of objects associated with this file. This will be + // more than 1 in the case of an archive. + int object_count_; + // File size. + off_t size_; + // A token used to lock the file. + Task_token token_; + // Buffered views into the file. + Views views_; + // List of views which were locked but had to be removed from views_ + // because they were not large enough. + Saved_views saved_views_; + // Total amount of space mapped into memory. This is only changed + // while the file is locked. When we unlock the file, we transfer + // the total to total_mapped_bytes, and reset this to zero. + size_t mapped_bytes_; + // Whether the file was released. + bool released_; + // A view containing the whole file. May be NULL if we mmap only + // the relevant parts of the file. Not NULL if: + // - Flag --mmap_whole_files is set (default on 64-bit hosts). + // - The contents was specified in the constructor. Used only for + // testing purposes). + View* whole_file_view_; +}; + +// A view of file data that persists even when the file is unlocked. +// Callers should destroy these when no longer required. These are +// obtained form File_read::get_lasting_view. They may only be +// destroyed when the underlying File_read is locked. + +class File_view +{ + public: + // This may only be called when the underlying File_read is locked. + ~File_view(); + + // Return a pointer to the data associated with this view. + const unsigned char* + data() const + { return this->data_; } + + private: + File_view(const File_view&); + File_view& operator=(const File_view&); + + friend class File_read; + + // Callers have to get these via File_read::get_lasting_view. + File_view(File_read& file, File_read::View* view, const unsigned char* data) + : file_(file), view_(view), data_(data) + { } + + File_read& file_; + File_read::View* view_; + const unsigned char* data_; +}; + +// All the information we hold for a single input file. This can be +// an object file, a shared library, or an archive. + +class Input_file +{ + public: + enum Format + { + FORMAT_NONE, + FORMAT_ELF, + FORMAT_BINARY + }; + + Input_file(const Input_file_argument* input_argument) + : input_argument_(input_argument), found_name_(), file_(), + is_in_sysroot_(false), format_(FORMAT_NONE) + { } + + // Create an input file given just a filename. + Input_file(const char* name); + + // Create an input file with the contents already provided. This is + // only used for testing. With this path, don't call the open + // method. + Input_file(const Task*, const char* name, const unsigned char* contents, + off_t size); + + // Return the command line argument. + const Input_file_argument* + input_file_argument() const + { return this->input_argument_; } + + // Return whether this is a file that we will search for in the list + // of directories. + bool + will_search_for() const; + + // Open the file. If the open fails, this will report an error and + // return false. If there is a search, it starts at directory + // *PINDEX. *PINDEX should be initialized to zero. It may be + // restarted to find the next file with a matching name by + // incrementing the result and calling this again. + bool + open(const Dirsearch&, const Task*, int* pindex); + + // Return the name given by the user. For -lc this will return "c". + const char* + name() const; + + // Return the file name. For -lc this will return something like + // "/usr/lib/libc.so". + const std::string& + filename() const + { return this->file_.filename(); } + + // Return the name under which we found the file, corresponding to + // the command line. For -lc this will return something like + // "libc.so". + const std::string& + found_name() const + { return this->found_name_; } + + // Return the position dependent options. + const Position_dependent_options& + options() const; + + // Return the file. + File_read& + file() + { return this->file_; } + + const File_read& + file() const + { return this->file_; } + + // Whether we found the file in a directory in the system root. + bool + is_in_sysroot() const + { return this->is_in_sysroot_; } + + // Whether this file is in a system directory. + bool + is_in_system_directory() const; + + // Return whether this file is to be read only for its symbols. + bool + just_symbols() const; + + // Return the format of the unconverted input file. + Format + format() const + { return this->format_; } + + // Try to find a file in the extra search dirs. Returns true on success. + static bool + try_extra_search_path(int* pindex, + const Input_file_argument* input_argument, + std::string filename, std::string* found_name, + std::string* namep); + + // Find the actual file. + static bool + find_file(const Dirsearch& dirpath, int* pindex, + const Input_file_argument* input_argument, + bool* is_in_sysroot, + std::string* found_name, std::string* namep); + + private: + Input_file(const Input_file&); + Input_file& operator=(const Input_file&); + + // Open a binary file. + bool + open_binary(const Task* task, const std::string& name); + + // The argument from the command line. + const Input_file_argument* input_argument_; + // The name under which we opened the file. This is like the name + // on the command line, but -lc turns into libc.so (or whatever). + // It only includes the full path if the path was on the command + // line. + std::string found_name_; + // The file after we open it. + File_read file_; + // Whether we found the file in a directory in the system root. + bool is_in_sysroot_; + // Format of unconverted input file. + Format format_; +}; + +} // end namespace gold + +#endif // !defined(GOLD_FILEREAD_H) diff --git a/binutils-2.25/gold/freebsd.h b/binutils-2.25/gold/freebsd.h new file mode 100644 index 00000000..3bdedceb --- /dev/null +++ b/binutils-2.25/gold/freebsd.h @@ -0,0 +1,103 @@ +// freebsd.h -- FreeBSD support for gold -*- C++ -*- + +// Copyright 2009, 2011, 2012 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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 "target.h" +#include "target-select.h" + +#ifndef GOLD_FREEBSD_H +#define GOLD_FREEBSD_H + +namespace gold +{ + +// FreeBSD 4.1 and later wants the EI_OSABI field in the ELF header to +// be set to ELFOSABI_FREEBSD. This is a target selector for targets +// which permit combining both FreeBSD and non-FreeBSD object files. + +class Target_selector_freebsd : public Target_selector +{ + public: + Target_selector_freebsd(int machine, int size, bool is_big_endian, + const char* bfd_name, + const char* freebsd_bfd_name, + const char* emulation) + : Target_selector(machine, size, is_big_endian, NULL, emulation), + bfd_name_(bfd_name), freebsd_bfd_name_(freebsd_bfd_name) + { } + + protected: + // If we see a FreeBSD input file, mark the output file as using + // FreeBSD. + virtual Target* + 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(osabi)); + return ret; + } + + // Recognize two names. + virtual Target* + do_recognize_by_bfd_name(const char* name) + { + if (strcmp(name, this->bfd_name_) == 0) + return this->instantiate_target(); + else if (strcmp(name, this->freebsd_bfd_name_) == 0) + { + Target* ret = this->instantiate_target(); + ret->set_osabi(elfcpp::ELFOSABI_FREEBSD); + return ret; + } + else + return NULL; + } + + // Print both names in --help output. + virtual void + do_supported_bfd_names(std::vector* names) + { + names->push_back(this->bfd_name_); + names->push_back(this->freebsd_bfd_name_); + } + + // Return appropriate BFD name. + virtual const char* + do_target_bfd_name(const Target* target) + { + if (!this->is_our_target(target)) + return NULL; + return (target->osabi() == elfcpp::ELFOSABI_FREEBSD + ? this->freebsd_bfd_name_ + : this->bfd_name_); + } + + private: + // The BFD name for the non-Freebsd target. + const char* bfd_name_; + // The BFD name for the Freebsd target. + const char* freebsd_bfd_name_; +}; + +} // end namespace gold + +#endif // !defined(GOLD_FREEBSD_H) diff --git a/binutils-2.25/gold/ftruncate.c b/binutils-2.25/gold/ftruncate.c new file mode 100644 index 00000000..102fcd12 --- /dev/null +++ b/binutils-2.25/gold/ftruncate.c @@ -0,0 +1,111 @@ +/* ftruncate emulations that work on some System V's. + This file is in the public domain. */ + +/* 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 + +/* Specification. */ +#include + +#include +#include + +extern int ftruncate (int, off_t); + +#ifdef F_CHSIZE + +int +ftruncate (int fd, off_t length) +{ + return fcntl (fd, F_CHSIZE, length); +} + +#else /* not F_CHSIZE */ +# ifdef F_FREESP + +/* By William Kucharski . */ + +# include +# include + +int +ftruncate (int fd, off_t length) +{ + struct flock fl; + struct stat filebuf; + + if (fstat (fd, &filebuf) < 0) + return -1; + + if (filebuf.st_size < length) + { + /* Extend file length. */ + if (lseek (fd, (length - 1), SEEK_SET) < 0) + return -1; + + /* Write a "0" byte. */ + if (write (fd, "", 1) != 1) + return -1; + } + else + { + + /* Truncate length. */ + + fl.l_whence = 0; + fl.l_len = 0; + fl.l_start = length; + fl.l_type = F_WRLCK; /* write lock on file space */ + + /* This relies on the *undocumented* F_FREESP argument to fcntl, + which truncates the file so that it ends at the position + indicated by fl.l_start. Will minor miracles never cease? */ + + if (fcntl (fd, F_FREESP, &fl) < 0) + return -1; + } + + return 0; +} + +# else /* not F_CHSIZE nor F_FREESP */ +# if HAVE_CHSIZE /* native Windows, e.g. mingw */ + +int +ftruncate (int fd, off_t length) +{ + return chsize (fd, length); +} + +# else /* not F_CHSIZE nor F_FREESP nor HAVE_CHSIZE */ + +# include + +int +ftruncate (int fd, off_t length) +{ + errno = EIO; + return -1; +} + +# endif /* not HAVE_CHSIZE */ +# endif /* not F_FREESP */ +#endif /* not F_CHSIZE */ diff --git a/binutils-2.25/gold/gc.cc b/binutils-2.25/gold/gc.cc new file mode 100644 index 00000000..7a594a51 --- /dev/null +++ b/binutils-2.25/gold/gc.cc @@ -0,0 +1,74 @@ +// gc.cc -- garbage collection of unused sections + +// Copyright 2009 Free Software Foundation, Inc. +// Written by Sriraman Tallam . + +// 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 "object.h" +#include "gc.h" +#include "symtab.h" + +namespace gold +{ + +// Garbage collection uses a worklist style algorithm to determine the +// transitive closure of all referenced sections. +void +Garbage_collection::do_transitive_closure() +{ + while (!this->worklist().empty()) + { + // Add elements from the work list to the referenced list + // one by one. + Section_id entry = this->worklist().front(); + this->worklist().pop(); + if (this->referenced_list().find(entry) + == this->referenced_list().end()) + { + this->referenced_list().insert(entry); + } + else + { + continue; + } + Garbage_collection::Section_ref::iterator find_it = + this->section_reloc_map().find(entry); + if (find_it == this->section_reloc_map().end()) + continue; + Garbage_collection::Sections_reachable v = find_it->second; + // Scan the vector of references for each work_list entry. + for (Garbage_collection::Sections_reachable::iterator it_v = v.begin(); + it_v != v.end(); + ++it_v) + { + // Do not add already processed sections to the work_list. + if (this->referenced_list().find(*it_v) + == this->referenced_list().end()) + { + this->worklist().push(*it_v); + } + } + } + this->worklist_ready(); +} + +} // End namespace gold. + diff --git a/binutils-2.25/gold/gc.h b/binutils-2.25/gold/gc.h new file mode 100644 index 00000000..4224a66e --- /dev/null +++ b/binutils-2.25/gold/gc.h @@ -0,0 +1,383 @@ +// gc.h -- garbage collection of unused sections + +// Copyright 2009, 2010, 2011, 2012 Free Software Foundation, Inc. +// Written by Sriraman Tallam . + +// 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. + +#ifndef GOLD_GC_H +#define GOLD_GC_H + +#include +#include + +#include "elfcpp.h" +#include "symtab.h" +#include "object.h" +#include "icf.h" + +namespace gold +{ + +class Object; + +template +class Sized_relobj_file; + +template +struct Reloc_types; + +class Output_section; +class General_options; +class Layout; + +class Garbage_collection +{ + public: + + typedef Unordered_set Sections_reachable; + typedef std::map Section_ref; + typedef std::queue Worklist_type; + // This maps the name of the section which can be represented as a C + // identifier (cident) to the list of sections that have that name. + // Different object files can have cident sections with the same name. + typedef std::map Cident_section_map; + + Garbage_collection() + : is_worklist_ready_(false) + { } + + // Accessor methods for the private members. + + Sections_reachable& + referenced_list() + { return referenced_list_; } + + Section_ref& + section_reloc_map() + { return this->section_reloc_map_; } + + Worklist_type& + worklist() + { return this->work_list_; } + + bool + is_worklist_ready() + { return this->is_worklist_ready_; } + + void + worklist_ready() + { this->is_worklist_ready_ = true; } + + void + do_transitive_closure(); + + bool + is_section_garbage(Object* obj, unsigned int shndx) + { return (this->referenced_list().find(Section_id(obj, shndx)) + == this->referenced_list().end()); } + + Cident_section_map* + cident_sections() + { return &cident_sections_; } + + void + add_cident_section(std::string section_name, + Section_id secn) + { this->cident_sections_[section_name].insert(secn); } + + // Add a reference from the SRC_SHNDX-th section of SRC_OBJECT to + // DST_SHNDX-th section of DST_OBJECT. + void + add_reference(Object* src_object, unsigned int src_shndx, + Object* dst_object, unsigned int dst_shndx) + { + Section_id src_id(src_object, src_shndx); + Section_id dst_id(dst_object, dst_shndx); + Section_ref::iterator p = this->section_reloc_map_.find(src_id); + if (p == this->section_reloc_map_.end()) + this->section_reloc_map_[src_id].insert(dst_id); + else + p->second.insert(dst_id); + } + + private: + + Worklist_type work_list_; + bool is_worklist_ready_; + Section_ref section_reloc_map_; + Sections_reachable referenced_list_; + Cident_section_map cident_sections_; +}; + +// Data to pass between successive invocations of do_layout +// in object.cc while garbage collecting. This data structure +// is filled by using the data from Read_symbols_data. + +struct Symbols_data +{ + // Section headers. + unsigned char* section_headers_data; + // Section names. + unsigned char* section_names_data; + // Size of section name data in bytes. + section_size_type section_names_size; + // Symbol data. + unsigned char* symbols_data; + // Size of symbol data in bytes. + section_size_type symbols_size; + // Offset of external symbols within symbol data. This structure + // sometimes contains only external symbols, in which case this will + // be zero. Sometimes it contains all symbols. + section_offset_type external_symbols_offset; + // Symbol names. + unsigned char* symbol_names_data; + // Size of symbol name data in bytes. + section_size_type symbol_names_size; +}; + +// Relocations of type SHT_REL store the addend value in their bytes. +// This function returns the size of the embedded addend which is +// nothing but the size of the relocation. + +template +inline unsigned int +get_embedded_addend_size(int sh_type, int r_type, Relobj* obj) +{ + if (sh_type != elfcpp::SHT_REL) + return 0; + Classify_reloc classify_reloc; + return classify_reloc.get_size_for_reloc(r_type, obj); +} + +// This function implements the generic part of reloc +// processing to map a section to all the sections it +// references through relocs. It is called only during +// garbage collection (--gc-sections) and identical code +// folding (--icf). + +template +inline void +gc_process_relocs( + Symbol_table* symtab, + Layout*, + Target_type* target, + Sized_relobj_file* src_obj, + unsigned int src_indx, + const unsigned char* prelocs, + size_t reloc_count, + Output_section*, + bool, + size_t local_count, + const unsigned char* plocal_syms) +{ + Scan scan; + + typedef typename Reloc_types::Reloc Reltype; + const int reloc_size = Reloc_types::reloc_size; + const int sym_size = elfcpp::Elf_sizes::sym_size; + + Icf::Sections_reachable_info* secvec = NULL; + Icf::Symbol_info* symvec = NULL; + Icf::Addend_info* addendvec = NULL; + Icf::Offset_info* offsetvec = NULL; + Icf::Reloc_addend_size_info* reloc_addend_size_vec = NULL; + bool is_icf_tracked = false; + const char* cident_section_name = NULL; + + std::string src_section_name = (parameters->options().icf_enabled() + ? src_obj->section_name(src_indx) + : ""); + + bool check_section_for_function_pointers = false; + + if (parameters->options().icf_enabled() + && is_section_foldable_candidate(src_section_name.c_str())) + { + is_icf_tracked = true; + Section_id src_id(src_obj, src_indx); + Icf::Reloc_info* reloc_info = + &symtab->icf()->reloc_info_list()[src_id]; + secvec = &reloc_info->section_info; + symvec = &reloc_info->symbol_info; + addendvec = &reloc_info->addend_info; + offsetvec = &reloc_info->offset_info; + reloc_addend_size_vec = &reloc_info->reloc_addend_size_info; + } + + check_section_for_function_pointers = + symtab->icf()->check_section_for_function_pointers(src_section_name, + target); + + for (size_t i = 0; i < reloc_count; ++i, prelocs += reloc_size) + { + Reltype reloc(prelocs); + typename elfcpp::Elf_types::Elf_WXword r_info = reloc.get_r_info(); + unsigned int r_sym = elfcpp::elf_r_sym(r_info); + unsigned int r_type = elfcpp::elf_r_type(r_info); + typename elfcpp::Elf_types::Elf_Swxword addend = + Reloc_types::get_reloc_addend_noerror(&reloc); + Object* dst_obj; + unsigned int dst_indx; + typedef typename elfcpp::Elf_types::Elf_Addr Address; + Address dst_off; + + if (r_sym < local_count) + { + gold_assert(plocal_syms != NULL); + typename elfcpp::Sym lsym(plocal_syms + + r_sym * sym_size); + dst_indx = lsym.get_st_shndx(); + bool is_ordinary; + dst_indx = src_obj->adjust_sym_shndx(r_sym, dst_indx, &is_ordinary); + dst_obj = src_obj; + dst_off = lsym.get_st_value() + addend; + + if (is_icf_tracked) + { + Address symvalue = dst_off - addend; + if (is_ordinary) + (*secvec).push_back(Section_id(dst_obj, dst_indx)); + else + (*secvec).push_back(Section_id(NULL, 0)); + (*symvec).push_back(NULL); + (*addendvec).push_back(std::make_pair( + static_cast(symvalue), + static_cast(addend))); + uint64_t reloc_offset = + convert_to_section_size_type(reloc.get_r_offset()); + (*offsetvec).push_back(reloc_offset); + (*reloc_addend_size_vec).push_back( + get_embedded_addend_size(sh_type, r_type, + src_obj)); + } + + // When doing safe folding, check to see if this relocation is that + // of a function pointer being taken. + if (is_ordinary + && check_section_for_function_pointers + && lsym.get_st_type() != elfcpp::STT_OBJECT + && scan.local_reloc_may_be_function_pointer(symtab, NULL, NULL, + src_obj, src_indx, + NULL, reloc, r_type, + lsym)) + symtab->icf()->set_section_has_function_pointers( + src_obj, lsym.get_st_shndx()); + + if (!is_ordinary || dst_indx == src_indx) + continue; + } + else + { + Symbol* gsym = src_obj->global_symbol(r_sym); + gold_assert(gsym != NULL); + if (gsym->is_forwarder()) + gsym = symtab->resolve_forwards(gsym); + + dst_obj = NULL; + dst_indx = 0; + bool is_ordinary = false; + if (gsym->source() == Symbol::FROM_OBJECT) + { + dst_obj = gsym->object(); + dst_indx = gsym->shndx(&is_ordinary); + } + dst_off = static_cast*>(gsym)->value(); + dst_off += addend; + + // When doing safe folding, check to see if this relocation is that + // of a function pointer being taken. + if (gsym->source() == Symbol::FROM_OBJECT + && check_section_for_function_pointers + && gsym->type() != elfcpp::STT_OBJECT + && (!is_ordinary + || scan.global_reloc_may_be_function_pointer( + symtab, NULL, NULL, src_obj, src_indx, NULL, reloc, + r_type, gsym))) + symtab->icf()->set_section_has_function_pointers(dst_obj, dst_indx); + + // If the symbol name matches '__start_XXX' then the section with + // the C identifier like name 'XXX' should not be garbage collected. + // A similar treatment to symbols with the name '__stop_XXX'. + if (is_prefix_of(cident_section_start_prefix, gsym->name())) + { + cident_section_name = (gsym->name() + + strlen(cident_section_start_prefix)); + } + else if (is_prefix_of(cident_section_stop_prefix, gsym->name())) + { + cident_section_name = (gsym->name() + + strlen(cident_section_stop_prefix)); + } + if (is_icf_tracked) + { + Address symvalue = dst_off - addend; + if (is_ordinary && gsym->source() == Symbol::FROM_OBJECT) + (*secvec).push_back(Section_id(dst_obj, dst_indx)); + else + (*secvec).push_back(Section_id(NULL, 0)); + (*symvec).push_back(gsym); + (*addendvec).push_back(std::make_pair( + static_cast(symvalue), + static_cast(addend))); + uint64_t reloc_offset = + convert_to_section_size_type(reloc.get_r_offset()); + (*offsetvec).push_back(reloc_offset); + (*reloc_addend_size_vec).push_back( + get_embedded_addend_size(sh_type, r_type, + src_obj)); + } + + if (gsym->source() != Symbol::FROM_OBJECT) + continue; + if (!is_ordinary) + continue; + } + if (parameters->options().gc_sections()) + { + symtab->gc()->add_reference(src_obj, src_indx, dst_obj, dst_indx); + parameters->sized_target() + ->gc_add_reference(symtab, src_obj, src_indx, + dst_obj, dst_indx, dst_off); + if (cident_section_name != NULL) + { + Garbage_collection::Cident_section_map::iterator ele = + symtab->gc()->cident_sections()->find(std::string(cident_section_name)); + if (ele == symtab->gc()->cident_sections()->end()) + continue; + Section_id src_id(src_obj, src_indx); + Garbage_collection::Sections_reachable& + v(symtab->gc()->section_reloc_map()[src_id]); + Garbage_collection::Sections_reachable& cident_secn(ele->second); + for (Garbage_collection::Sections_reachable::iterator it_v + = cident_secn.begin(); + it_v != cident_secn.end(); + ++it_v) + { + v.insert(*it_v); + } + } + } + } + return; +} + +} // End of namespace gold. + +#endif diff --git a/binutils-2.25/gold/gdb-index.cc b/binutils-2.25/gold/gdb-index.cc new file mode 100644 index 00000000..3b700686 --- /dev/null +++ b/binutils-2.25/gold/gdb-index.cc @@ -0,0 +1,1343 @@ +// gdb-index.cc -- generate .gdb_index section for fast debug lookup + +// Copyright 2012 Free Software Foundation, Inc. +// Written by Cary Coutant . + +// 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 "gdb-index.h" +#include "dwarf_reader.h" +#include "dwarf.h" +#include "object.h" +#include "output.h" +#include "demangle.h" + +namespace gold +{ + +const int gdb_index_version = 5; + +// Sizes of various records in the .gdb_index section. +const int gdb_index_offset_size = 4; +const int gdb_index_hdr_size = 6 * gdb_index_offset_size; +const int gdb_index_cu_size = 16; +const int gdb_index_tu_size = 24; +const int gdb_index_addr_size = 16 + gdb_index_offset_size; +const int gdb_index_sym_size = 2 * gdb_index_offset_size; + +// This class manages the hashed symbol table for the .gdb_index section. +// It is essentially equivalent to the hashtab implementation in libiberty, +// but is copied into gdb sources and here for compatibility because its +// data structure is exposed on disk. + +template +class Gdb_hashtab +{ + public: + Gdb_hashtab() + : size_(0), capacity_(0), hashtab_(NULL) + { } + + ~Gdb_hashtab() + { + for (size_t i = 0; i < this->capacity_; ++i) + if (this->hashtab_[i] != NULL) + delete this->hashtab_[i]; + delete[] this->hashtab_; + } + + // Add a symbol. + T* + add(T* symbol) + { + // Resize the hash table if necessary. + if (4 * this->size_ / 3 >= this->capacity_) + this->expand(); + + T** slot = this->find_slot(symbol); + if (*slot == NULL) + { + ++this->size_; + *slot = symbol; + } + + return *slot; + } + + // Return the current size. + size_t + size() const + { return this->size_; } + + // Return the current capacity. + size_t + capacity() const + { return this->capacity_; } + + // Return the contents of slot N. + T* + operator[](size_t n) + { return this->hashtab_[n]; } + + private: + // Find a symbol in the hash table, or return an empty slot if + // the symbol is not in the table. + T** + find_slot(T* symbol) + { + unsigned int index = symbol->hash() & (this->capacity_ - 1); + unsigned int step = ((symbol->hash() * 17) & (this->capacity_ - 1)) | 1; + + for (;;) + { + if (this->hashtab_[index] == NULL + || this->hashtab_[index]->equal(symbol)) + return &this->hashtab_[index]; + index = (index + step) & (this->capacity_ - 1); + } + } + + // Expand the hash table. + void + expand() + { + if (this->capacity_ == 0) + { + // Allocate the hash table for the first time. + this->capacity_ = Gdb_hashtab::initial_size; + this->hashtab_ = new T*[this->capacity_]; + memset(this->hashtab_, 0, this->capacity_ * sizeof(T*)); + } + else + { + // Expand and rehash. + unsigned int old_cap = this->capacity_; + T** old_hashtab = this->hashtab_; + this->capacity_ *= 2; + this->hashtab_ = new T*[this->capacity_]; + memset(this->hashtab_, 0, this->capacity_ * sizeof(T*)); + for (size_t i = 0; i < old_cap; ++i) + { + if (old_hashtab[i] != NULL) + { + T** slot = this->find_slot(old_hashtab[i]); + *slot = old_hashtab[i]; + } + } + delete[] old_hashtab; + } + } + + // Initial size of the hash table; must be a power of 2. + static const int initial_size = 1024; + size_t size_; + size_t capacity_; + T** hashtab_; +}; + +// The hash function for strings in the mapped index. This is copied +// directly from gdb/dwarf2read.c. + +static unsigned int +mapped_index_string_hash(const unsigned char* str) +{ + unsigned int r = 0; + unsigned char c; + + while ((c = *str++) != 0) + { + if (gdb_index_version >= 5) + c = tolower (c); + r = r * 67 + c - 113; + } + + return r; +} + +// A specialization of Dwarf_info_reader, for building the .gdb_index. + +class Gdb_index_info_reader : public Dwarf_info_reader +{ + public: + Gdb_index_info_reader(bool is_type_unit, + Relobj* object, + const unsigned char* symbols, + off_t symbols_size, + unsigned int shndx, + unsigned int reloc_shndx, + unsigned int reloc_type, + Gdb_index* gdb_index) + : Dwarf_info_reader(is_type_unit, object, symbols, symbols_size, shndx, + reloc_shndx, reloc_type), + gdb_index_(gdb_index), cu_index_(0), cu_language_(0) + { } + + ~Gdb_index_info_reader() + { this->clear_declarations(); } + + // Print usage statistics. + static void + print_stats(); + + protected: + // Visit a compilation unit. + virtual void + visit_compilation_unit(off_t cu_offset, off_t cu_length, Dwarf_die*); + + // Visit a type unit. + virtual void + visit_type_unit(off_t tu_offset, off_t type_offset, uint64_t signature, + Dwarf_die*); + + private: + // A map for recording DIEs we've seen that may be referred to be + // later DIEs (via DW_AT_specification or DW_AT_abstract_origin). + // The map is indexed by a DIE offset within the compile unit. + // PARENT_OFFSET_ is the offset of the DIE that represents the + // outer context, and NAME_ is a pointer to a component of the + // fully-qualified name. + // Normally, the names we point to are in a string table, so we don't + // have to manage them, but when we have a fully-qualified name + // computed, we put it in the table, and set PARENT_OFFSET_ to -1 + // indicate a string that we are managing. + struct Declaration_pair + { + Declaration_pair(off_t parent_offset, const char* name) + : parent_offset_(parent_offset), name_(name) + { } + + off_t parent_offset_; + const char* name_; + }; + typedef Unordered_map Declaration_map; + + // Visit a top-level DIE. + void + visit_top_die(Dwarf_die* die); + + // Visit the children of a DIE. + void + visit_children(Dwarf_die* die, Dwarf_die* context); + + // Visit a DIE. + void + visit_die(Dwarf_die* die, Dwarf_die* context); + + // Visit the children of a DIE. + void + visit_children_for_decls(Dwarf_die* die); + + // Visit a DIE. + void + visit_die_for_decls(Dwarf_die* die, Dwarf_die* context); + + // Guess a fully-qualified name for a class type, based on member function + // linkage names. + std::string + guess_full_class_name(Dwarf_die* die); + + // Add a declaration DIE to the table of declarations. + void + add_declaration(Dwarf_die* die, Dwarf_die* context); + + // Add a declaration whose fully-qualified name is already known. + void + add_declaration_with_full_name(Dwarf_die* die, const char* full_name); + + // Return the context for a DIE whose parent is at DIE_OFFSET. + std::string + get_context(off_t die_offset); + + // Construct a fully-qualified name for DIE. + std::string + get_qualified_name(Dwarf_die* die, Dwarf_die* context); + + // Record the address ranges for a compilation unit. + void + record_cu_ranges(Dwarf_die* die); + + // Wrapper for read_pubtable. + bool + read_pubnames_and_pubtypes(Dwarf_die* die); + + // Read the .debug_pubnames and .debug_pubtypes tables. + bool + read_pubtable(Dwarf_pubnames_table* table, off_t offset); + + // Clear the declarations map. + void + clear_declarations(); + + // The Gdb_index section. + Gdb_index* gdb_index_; + // The current CU index (negative for a TU). + int cu_index_; + // The language of the current CU or TU. + unsigned int cu_language_; + // Map from DIE offset to (parent offset, name) pair, + // for DW_AT_specification. + Declaration_map declarations_; + + // Statistics. + // Total number of DWARF compilation units processed. + static unsigned int dwarf_cu_count; + // Number of DWARF compilation units with pubnames/pubtypes. + static unsigned int dwarf_cu_nopubnames_count; + // Total number of DWARF type units processed. + static unsigned int dwarf_tu_count; + // Number of DWARF type units with pubnames/pubtypes. + static unsigned int dwarf_tu_nopubnames_count; +}; + +// Total number of DWARF compilation units processed. +unsigned int Gdb_index_info_reader::dwarf_cu_count = 0; +// Number of DWARF compilation units without pubnames/pubtypes. +unsigned int Gdb_index_info_reader::dwarf_cu_nopubnames_count = 0; +// Total number of DWARF type units processed. +unsigned int Gdb_index_info_reader::dwarf_tu_count = 0; +// Number of DWARF type units without pubnames/pubtypes. +unsigned int Gdb_index_info_reader::dwarf_tu_nopubnames_count = 0; + +// Process a compilation unit and parse its child DIE. + +void +Gdb_index_info_reader::visit_compilation_unit(off_t cu_offset, off_t cu_length, + Dwarf_die* root_die) +{ + ++Gdb_index_info_reader::dwarf_cu_count; + this->cu_index_ = this->gdb_index_->add_comp_unit(cu_offset, cu_length); + this->visit_top_die(root_die); +} + +// Process a type unit and parse its child DIE. + +void +Gdb_index_info_reader::visit_type_unit(off_t tu_offset, off_t type_offset, + uint64_t signature, Dwarf_die* root_die) +{ + ++Gdb_index_info_reader::dwarf_tu_count; + // Use a negative index to flag this as a TU instead of a CU. + this->cu_index_ = -1 - this->gdb_index_->add_type_unit(tu_offset, type_offset, + signature); + this->visit_top_die(root_die); +} + +// Process a top-level DIE. +// For compile_unit DIEs, record the address ranges. For all +// interesting tags, add qualified names to the symbol table +// and process interesting children. We may need to process +// certain children just for saving declarations that might be +// referenced by later DIEs with a DW_AT_specification attribute. + +void +Gdb_index_info_reader::visit_top_die(Dwarf_die* die) +{ + this->clear_declarations(); + + switch (die->tag()) + { + case elfcpp::DW_TAG_compile_unit: + case elfcpp::DW_TAG_type_unit: + this->cu_language_ = die->int_attribute(elfcpp::DW_AT_language); + // Check for languages that require specialized knowledge to + // construct fully-qualified names, that we don't yet support. + if (this->cu_language_ == elfcpp::DW_LANG_Ada83 + || this->cu_language_ == elfcpp::DW_LANG_Fortran77 + || this->cu_language_ == elfcpp::DW_LANG_Fortran90 + || this->cu_language_ == elfcpp::DW_LANG_Java + || this->cu_language_ == elfcpp::DW_LANG_Ada95 + || this->cu_language_ == elfcpp::DW_LANG_Fortran95) + { + gold_warning(_("%s: --gdb-index currently supports " + "only C and C++ languages"), + this->object()->name().c_str()); + return; + } + if (die->tag() == elfcpp::DW_TAG_compile_unit) + this->record_cu_ranges(die); + // If there is a pubnames and/or pubtypes section for this + // compilation unit, use those; otherwise, parse the DWARF + // info to extract the names. + if (!this->read_pubnames_and_pubtypes(die)) + { + if (die->tag() == elfcpp::DW_TAG_compile_unit) + ++Gdb_index_info_reader::dwarf_cu_nopubnames_count; + else + ++Gdb_index_info_reader::dwarf_tu_nopubnames_count; + this->visit_children(die, NULL); + } + break; + default: + // The top level DIE should be one of the above. + gold_warning(_("%s: top level DIE is not DW_TAG_compile_unit " + "or DW_TAG_type_unit"), + this->object()->name().c_str()); + return; + } + +} + +// Visit the children of PARENT, looking for symbols to add to the index. +// CONTEXT points to the DIE to use for constructing the qualified name -- +// NULL if PARENT is the top-level DIE; otherwise it is the same as PARENT. + +void +Gdb_index_info_reader::visit_children(Dwarf_die* parent, Dwarf_die* context) +{ + off_t next_offset = 0; + for (off_t die_offset = parent->child_offset(); + die_offset != 0; + die_offset = next_offset) + { + Dwarf_die die(this, die_offset, parent); + if (die.tag() == 0) + break; + this->visit_die(&die, context); + next_offset = die.sibling_offset(); + } +} + +// Visit a child DIE, looking for symbols to add to the index. +// CONTEXT is the parent DIE, used for constructing the qualified name; +// it is NULL if the parent DIE is the top-level DIE. + +void +Gdb_index_info_reader::visit_die(Dwarf_die* die, Dwarf_die* context) +{ + switch (die->tag()) + { + case elfcpp::DW_TAG_subprogram: + case elfcpp::DW_TAG_constant: + case elfcpp::DW_TAG_variable: + case elfcpp::DW_TAG_enumerator: + case elfcpp::DW_TAG_base_type: + if (die->is_declaration()) + this->add_declaration(die, context); + else + { + // If the DIE is not a declaration, add it to the index. + std::string full_name = this->get_qualified_name(die, context); + if (!full_name.empty()) + this->gdb_index_->add_symbol(this->cu_index_, full_name.c_str()); + } + break; + case elfcpp::DW_TAG_typedef: + case elfcpp::DW_TAG_union_type: + case elfcpp::DW_TAG_class_type: + case elfcpp::DW_TAG_interface_type: + case elfcpp::DW_TAG_structure_type: + case elfcpp::DW_TAG_enumeration_type: + case elfcpp::DW_TAG_subrange_type: + case elfcpp::DW_TAG_namespace: + { + std::string full_name; + + // For classes at the top level, we need to look for a + // member function with a linkage name in order to get + // the properly-canonicalized name. + if (context == NULL + && (die->tag() == elfcpp::DW_TAG_class_type + || die->tag() == elfcpp::DW_TAG_structure_type + || die->tag() == elfcpp::DW_TAG_union_type)) + full_name.assign(this->guess_full_class_name(die)); + + // Because we will visit the children, we need to add this DIE + // to the declarations table. + if (full_name.empty()) + this->add_declaration(die, context); + else + this->add_declaration_with_full_name(die, full_name.c_str()); + + // If the DIE is not a declaration, add it to the index. + // Gdb stores a namespace in the index even when it is + // a declaration. + if (die->tag() == elfcpp::DW_TAG_namespace + || !die->is_declaration()) + { + if (full_name.empty()) + full_name = this->get_qualified_name(die, context); + if (!full_name.empty()) + this->gdb_index_->add_symbol(this->cu_index_, + full_name.c_str()); + } + + // We're interested in the children only for namespaces and + // enumeration types. For enumeration types, we do not include + // the enumeration tag as part of the full name. For other tags, + // visit the children only to collect declarations. + if (die->tag() == elfcpp::DW_TAG_namespace + || die->tag() == elfcpp::DW_TAG_enumeration_type) + this->visit_children(die, die); + else + this->visit_children_for_decls(die); + } + break; + default: + break; + } +} + +// Visit the children of PARENT, looking only for declarations that +// may be referenced by later specification DIEs. + +void +Gdb_index_info_reader::visit_children_for_decls(Dwarf_die* parent) +{ + off_t next_offset = 0; + for (off_t die_offset = parent->child_offset(); + die_offset != 0; + die_offset = next_offset) + { + Dwarf_die die(this, die_offset, parent); + if (die.tag() == 0) + break; + this->visit_die_for_decls(&die, parent); + next_offset = die.sibling_offset(); + } +} + +// Visit a child DIE, looking only for declarations that +// may be referenced by later specification DIEs. + +void +Gdb_index_info_reader::visit_die_for_decls(Dwarf_die* die, Dwarf_die* context) +{ + switch (die->tag()) + { + case elfcpp::DW_TAG_subprogram: + case elfcpp::DW_TAG_constant: + case elfcpp::DW_TAG_variable: + case elfcpp::DW_TAG_enumerator: + case elfcpp::DW_TAG_base_type: + { + if (die->is_declaration()) + this->add_declaration(die, context); + } + break; + case elfcpp::DW_TAG_typedef: + case elfcpp::DW_TAG_union_type: + case elfcpp::DW_TAG_class_type: + case elfcpp::DW_TAG_interface_type: + case elfcpp::DW_TAG_structure_type: + case elfcpp::DW_TAG_enumeration_type: + case elfcpp::DW_TAG_subrange_type: + case elfcpp::DW_TAG_namespace: + { + if (die->is_declaration()) + this->add_declaration(die, context); + this->visit_children_for_decls(die); + } + break; + default: + break; + } +} + +// Extract the class name from the linkage name of a member function. +// This code is adapted from ../gdb/cp-support.c. + +#define d_left(dc) (dc)->u.s_binary.left +#define d_right(dc) (dc)->u.s_binary.right + +static char* +class_name_from_linkage_name(const char* linkage_name) +{ + void* storage; + struct demangle_component* tree = + cplus_demangle_v3_components(linkage_name, DMGL_NO_OPTS, &storage); + if (tree == NULL) + return NULL; + + int done = 0; + + // First strip off any qualifiers, if we have a function or + // method. + while (!done) + switch (tree->type) + { + case DEMANGLE_COMPONENT_CONST: + case DEMANGLE_COMPONENT_RESTRICT: + case DEMANGLE_COMPONENT_VOLATILE: + case DEMANGLE_COMPONENT_CONST_THIS: + case DEMANGLE_COMPONENT_RESTRICT_THIS: + case DEMANGLE_COMPONENT_VOLATILE_THIS: + case DEMANGLE_COMPONENT_VENDOR_TYPE_QUAL: + tree = d_left(tree); + break; + default: + done = 1; + break; + } + + // If what we have now is a function, discard the argument list. + if (tree->type == DEMANGLE_COMPONENT_TYPED_NAME) + tree = d_left(tree); + + // If what we have now is a template, strip off the template + // arguments. The left subtree may be a qualified name. + if (tree->type == DEMANGLE_COMPONENT_TEMPLATE) + tree = d_left(tree); + + // What we have now should be a name, possibly qualified. + // Additional qualifiers could live in the left subtree or the right + // subtree. Find the last piece. + done = 0; + struct demangle_component* prev_comp = NULL; + struct demangle_component* cur_comp = tree; + while (!done) + switch (cur_comp->type) + { + case DEMANGLE_COMPONENT_QUAL_NAME: + case DEMANGLE_COMPONENT_LOCAL_NAME: + prev_comp = cur_comp; + cur_comp = d_right(cur_comp); + break; + case DEMANGLE_COMPONENT_TEMPLATE: + case DEMANGLE_COMPONENT_NAME: + case DEMANGLE_COMPONENT_CTOR: + case DEMANGLE_COMPONENT_DTOR: + case DEMANGLE_COMPONENT_OPERATOR: + case DEMANGLE_COMPONENT_EXTENDED_OPERATOR: + done = 1; + break; + default: + done = 1; + cur_comp = NULL; + break; + } + + char* ret = NULL; + if (cur_comp != NULL && prev_comp != NULL) + { + // We want to discard the rightmost child of PREV_COMP. + *prev_comp = *d_left(prev_comp); + size_t allocated_size; + ret = cplus_demangle_print(DMGL_NO_OPTS, tree, 30, &allocated_size); + } + + free(storage); + return ret; +} + +// Guess a fully-qualified name for a class type, based on member function +// linkage names. This is needed for class/struct/union types at the +// top level, because GCC does not always properly embed them within +// the namespace. As in gdb, we look for a member function with a linkage +// name and extract the qualified name from the demangled name. + +std::string +Gdb_index_info_reader::guess_full_class_name(Dwarf_die* die) +{ + std::string full_name; + off_t next_offset = 0; + + // This routine scans ahead in the DIE structure, possibly advancing + // the relocation tracker beyond the current DIE. We need to checkpoint + // the tracker and reset it when we're done. + uint64_t checkpoint = this->get_reloc_checkpoint(); + + for (off_t child_offset = die->child_offset(); + child_offset != 0; + child_offset = next_offset) + { + Dwarf_die child(this, child_offset, die); + if (child.tag() == 0) + break; + if (child.tag() == elfcpp::DW_TAG_subprogram) + { + const char* linkage_name = child.linkage_name(); + if (linkage_name != NULL) + { + char* guess = class_name_from_linkage_name(linkage_name); + if (guess != NULL) + { + full_name.assign(guess); + free(guess); + break; + } + } + } + next_offset = child.sibling_offset(); + } + + this->reset_relocs(checkpoint); + return full_name; +} + +// Add a declaration DIE to the table of declarations. + +void +Gdb_index_info_reader::add_declaration(Dwarf_die* die, Dwarf_die* context) +{ + const char* name = die->name(); + + off_t parent_offset = context != NULL ? context->offset() : 0; + + // If this DIE has a DW_AT_specification or DW_AT_abstract_origin + // attribute, use the parent and name from the earlier declaration. + off_t spec = die->specification(); + if (spec == 0) + spec = die->abstract_origin(); + if (spec > 0) + { + Declaration_map::iterator it = this->declarations_.find(spec); + if (it != this->declarations_.end()) + { + parent_offset = it->second.parent_offset_; + name = it->second.name_; + } + } + + if (name == NULL) + { + if (die->tag() == elfcpp::DW_TAG_namespace) + name = "(anonymous namespace)"; + else if (die->tag() == elfcpp::DW_TAG_union_type) + name = "(anonymous union)"; + else + name = "(unknown)"; + } + + Declaration_pair decl(parent_offset, name); + this->declarations_.insert(std::make_pair(die->offset(), decl)); +} + +// Add a declaration whose fully-qualified name is already known. +// In the case where we had to get the canonical name by demangling +// a linkage name, this ensures we use that name instead of the one +// provided in DW_AT_name. + +void +Gdb_index_info_reader::add_declaration_with_full_name( + Dwarf_die* die, + const char* full_name) +{ + // We need to copy the name. + int len = strlen(full_name); + char* copy = new char[len + 1]; + memcpy(copy, full_name, len + 1); + + // Flag that we now manage the memory this points to. + Declaration_pair decl(-1, copy); + this->declarations_.insert(std::make_pair(die->offset(), decl)); +} + +// Return the context for a DIE whose parent is at DIE_OFFSET. + +std::string +Gdb_index_info_reader::get_context(off_t die_offset) +{ + std::string context; + Declaration_map::iterator it = this->declarations_.find(die_offset); + if (it != this->declarations_.end()) + { + off_t parent_offset = it->second.parent_offset_; + if (parent_offset > 0) + { + context = get_context(parent_offset); + context.append("::"); + } + if (it->second.name_ != NULL) + context.append(it->second.name_); + } + return context; +} + +// Construct the fully-qualified name for DIE. + +std::string +Gdb_index_info_reader::get_qualified_name(Dwarf_die* die, Dwarf_die* context) +{ + std::string full_name; + const char* name = die->name(); + + off_t parent_offset = context != NULL ? context->offset() : 0; + + // If this DIE has a DW_AT_specification or DW_AT_abstract_origin + // attribute, use the parent and name from the earlier declaration. + off_t spec = die->specification(); + if (spec == 0) + spec = die->abstract_origin(); + if (spec > 0) + { + Declaration_map::iterator it = this->declarations_.find(spec); + if (it != this->declarations_.end()) + { + parent_offset = it->second.parent_offset_; + name = it->second.name_; + } + } + + if (name == NULL && die->tag() == elfcpp::DW_TAG_namespace) + name = "(anonymous namespace)"; + else if (name == NULL) + return full_name; + + // If this is an enumerator constant, skip the immediate parent, + // which is the enumeration tag. + if (die->tag() == elfcpp::DW_TAG_enumerator) + { + Declaration_map::iterator it = this->declarations_.find(parent_offset); + if (it != this->declarations_.end()) + parent_offset = it->second.parent_offset_; + } + + if (parent_offset > 0) + { + full_name.assign(this->get_context(parent_offset)); + full_name.append("::"); + } + full_name.append(name); + + return full_name; +} + +// Record the address ranges for a compilation unit. + +void +Gdb_index_info_reader::record_cu_ranges(Dwarf_die* die) +{ + unsigned int shndx; + unsigned int shndx2; + + off_t ranges_offset = die->ref_attribute(elfcpp::DW_AT_ranges, &shndx); + if (ranges_offset != -1) + { + Dwarf_range_list* ranges = this->read_range_list(shndx, ranges_offset); + if (ranges != NULL) + this->gdb_index_->add_address_range_list(this->object(), + this->cu_index_, ranges); + return; + } + + off_t low_pc = die->address_attribute(elfcpp::DW_AT_low_pc, &shndx); + off_t high_pc = die->address_attribute(elfcpp::DW_AT_high_pc, &shndx2); + if (high_pc == -1) + { + high_pc = die->uint_attribute(elfcpp::DW_AT_high_pc); + high_pc += low_pc; + shndx2 = shndx; + } + if ((low_pc != 0 || high_pc != 0) && low_pc != -1) + { + if (shndx != shndx2) + { + gold_warning(_("%s: DWARF info may be corrupt; low_pc and high_pc " + "are in different sections"), + this->object()->name().c_str()); + return; + } + if (shndx == 0 || this->object()->is_section_included(shndx)) + { + Dwarf_range_list* ranges = new Dwarf_range_list(); + ranges->add(shndx, low_pc, high_pc); + this->gdb_index_->add_address_range_list(this->object(), + this->cu_index_, ranges); + } + } +} + +// Read table and add the relevant names to the index. Returns true +// if any names were added. + +bool +Gdb_index_info_reader::read_pubtable(Dwarf_pubnames_table* table, off_t offset) +{ + // If we couldn't read the section when building the cu_pubname_map, + // then we won't find any pubnames now. + if (table == NULL) + return false; + + if (!table->read_header(offset)) + return false; + while (true) + { + const char* name = table->next_name(); + if (name == NULL) + break; + + this->gdb_index_->add_symbol(this->cu_index_, name); + } + return true; +} + +// Read the .debug_pubnames and .debug_pubtypes tables for the CU or TU. +// Returns TRUE if either a pubnames or pubtypes section was found. + +bool +Gdb_index_info_reader::read_pubnames_and_pubtypes(Dwarf_die* die) +{ + // We use stmt_list_off as a unique identifier for the + // compilation unit and its associated type units. + unsigned int shndx; + off_t stmt_list_off = die->ref_attribute (elfcpp::DW_AT_stmt_list, + &shndx); + // Look for the attr as either a flag or a ref. + off_t offset = die->ref_attribute(elfcpp::DW_AT_GNU_pubnames, &shndx); + + // Newer versions of GCC generate CUs, but not TUs, with + // DW_AT_FORM_flag_present. + unsigned int flag = die->uint_attribute(elfcpp::DW_AT_GNU_pubnames); + if (offset == -1 && flag == 0) + { + // Didn't find the attribute. + if (die->tag() == elfcpp::DW_TAG_type_unit) + { + // If die is a TU, then it might correspond to a CU which we + // have read. If it does, then no need to read the pubnames. + // If it doesn't, then the caller will have to parse the + // dies manually to find the names. + return this->gdb_index_->pubnames_read(this->object(), + stmt_list_off); + } + else + { + // No attribute on the CU means that no pubnames were read. + return false; + } + } + + // We found the attribute, so we can check if the corresponding + // pubnames have been read. + if (this->gdb_index_->pubnames_read(this->object(), stmt_list_off)) + return true; + + this->gdb_index_->set_pubnames_read(this->object(), stmt_list_off); + + // We have an attribute, and the pubnames haven't been read, so read + // them. + bool names = false; + // In some of the cases, we could rely on the previous value of + // offset here, but sorting out which cases complicates the logic + // enough that it isn't worth it. So just look up the offset again. + offset = this->gdb_index_->find_pubname_offset(this->cu_offset()); + names = this->read_pubtable(this->gdb_index_->pubnames_table(), offset); + + bool types = false; + offset = this->gdb_index_->find_pubtype_offset(this->cu_offset()); + types = this->read_pubtable(this->gdb_index_->pubtypes_table(), offset); + return names || types; +} + +// Clear the declarations map. +void +Gdb_index_info_reader::clear_declarations() +{ + // Free strings in memory we manage. + for (Declaration_map::iterator it = this->declarations_.begin(); + it != this->declarations_.end(); + ++it) + { + if (it->second.parent_offset_ == -1) + delete[] it->second.name_; + } + + this->declarations_.clear(); +} + +// Print usage statistics. +void +Gdb_index_info_reader::print_stats() +{ + fprintf(stderr, _("%s: DWARF CUs: %u\n"), + program_name, Gdb_index_info_reader::dwarf_cu_count); + fprintf(stderr, _("%s: DWARF CUs without pubnames/pubtypes: %u\n"), + program_name, Gdb_index_info_reader::dwarf_cu_nopubnames_count); + fprintf(stderr, _("%s: DWARF TUs: %u\n"), + program_name, Gdb_index_info_reader::dwarf_tu_count); + fprintf(stderr, _("%s: DWARF TUs without pubnames/pubtypes: %u\n"), + program_name, Gdb_index_info_reader::dwarf_tu_nopubnames_count); +} + +// Class Gdb_index. + +// Construct the .gdb_index section. + +Gdb_index::Gdb_index(Output_section* gdb_index_section) + : Output_section_data(4), + pubnames_table_(NULL), + pubtypes_table_(NULL), + gdb_index_section_(gdb_index_section), + comp_units_(), + type_units_(), + ranges_(), + cu_vector_list_(), + cu_vector_offsets_(NULL), + stringpool_(), + tu_offset_(0), + addr_offset_(0), + symtab_offset_(0), + cu_pool_offset_(0), + stringpool_offset_(0), + pubnames_object_(NULL), + stmt_list_offset_(-1) +{ + this->gdb_symtab_ = new Gdb_hashtab(); +} + +Gdb_index::~Gdb_index() +{ + // Free the memory used by the symbol table. + delete this->gdb_symtab_; + // Free the memory used by the CU vectors. + for (unsigned int i = 0; i < this->cu_vector_list_.size(); ++i) + delete this->cu_vector_list_[i]; +} + + +// Scan the pubnames and pubtypes sections and build a map of the +// various cus and tus they refer to, so we can process the entries +// when we encounter the die for that cu or tu. +// Return the just-read table so it can be cached. + +Dwarf_pubnames_table* +Gdb_index::map_pubtable_to_dies(unsigned int attr, + Gdb_index_info_reader* dwinfo, + Relobj* object, + const unsigned char* symbols, + off_t symbols_size) +{ + uint64_t section_offset = 0; + Dwarf_pubnames_table* table; + Pubname_offset_map* map; + + if (attr == elfcpp::DW_AT_GNU_pubnames) + { + table = new Dwarf_pubnames_table(dwinfo, false); + map = &this->cu_pubname_map_; + } + else + { + table = new Dwarf_pubnames_table(dwinfo, true); + map = &this->cu_pubtype_map_; + } + + map->clear(); + if (!table->read_section(object, symbols, symbols_size)) + return NULL; + + while (table->read_header(section_offset)) + { + map->insert(std::make_pair(table->cu_offset(), section_offset)); + section_offset += table->subsection_size(); + } + + return table; +} + +// Wrapper for map_pubtable_to_dies + +void +Gdb_index::map_pubnames_and_types_to_dies(Gdb_index_info_reader* dwinfo, + Relobj* object, + const unsigned char* symbols, + off_t symbols_size) +{ + // This is a new object, so reset the relevant variables. + this->pubnames_object_ = object; + this->stmt_list_offset_ = -1; + + delete this->pubnames_table_; + this->pubnames_table_ + = this->map_pubtable_to_dies(elfcpp::DW_AT_GNU_pubnames, dwinfo, + object, symbols, symbols_size); + delete this->pubtypes_table_; + this->pubtypes_table_ + = this->map_pubtable_to_dies(elfcpp::DW_AT_GNU_pubtypes, dwinfo, + object, symbols, symbols_size); +} + +// Given a cu_offset, find the associated section of the pubnames +// table. + +off_t +Gdb_index::find_pubname_offset(off_t cu_offset) +{ + Pubname_offset_map::iterator it = this->cu_pubname_map_.find(cu_offset); + if (it != this->cu_pubname_map_.end()) + return it->second; + return -1; +} + +// Given a cu_offset, find the associated section of the pubnames +// table. + +off_t +Gdb_index::find_pubtype_offset(off_t cu_offset) +{ + Pubname_offset_map::iterator it = this->cu_pubtype_map_.find(cu_offset); + if (it != this->cu_pubtype_map_.end()) + return it->second; + return -1; +} + +// Scan a .debug_info or .debug_types input section. + +void +Gdb_index::scan_debug_info(bool is_type_unit, + Relobj* object, + const unsigned char* symbols, + off_t symbols_size, + unsigned int shndx, + unsigned int reloc_shndx, + unsigned int reloc_type) +{ + Gdb_index_info_reader dwinfo(is_type_unit, object, + symbols, symbols_size, + shndx, reloc_shndx, + reloc_type, this); + if (object != this->pubnames_object_) + map_pubnames_and_types_to_dies(&dwinfo, object, symbols, symbols_size); + dwinfo.parse(); +} + +// Add a symbol. + +void +Gdb_index::add_symbol(int cu_index, const char* sym_name) +{ + unsigned int hash = mapped_index_string_hash( + reinterpret_cast(sym_name)); + Gdb_symbol* sym = new Gdb_symbol(); + this->stringpool_.add(sym_name, true, &sym->name_key); + sym->hashval = hash; + sym->cu_vector_index = 0; + + Gdb_symbol* found = this->gdb_symtab_->add(sym); + if (found == sym) + { + // New symbol -- allocate a new CU index vector. + found->cu_vector_index = this->cu_vector_list_.size(); + this->cu_vector_list_.push_back(new Cu_vector()); + } + else + { + // Found an existing symbol -- append to the existing + // CU index vector. + delete sym; + } + + // Add the CU index to the vector list for this symbol, + // if it's not already on the list. We only need to + // check the last added entry. + Cu_vector* cu_vec = this->cu_vector_list_[found->cu_vector_index]; + if (cu_vec->size() == 0 || cu_vec->back() != cu_index) + cu_vec->push_back(cu_index); +} + +// Return TRUE if we have already processed the pubnames associated +// with the statement list at the given OFFSET. + +bool +Gdb_index::pubnames_read(const Relobj* object, off_t offset) +{ + bool ret = (this->pubnames_object_ == object + && this->stmt_list_offset_ == offset); + return ret; +} + +// Record that we have processed the pubnames associated with the +// statement list for OBJECT at the given OFFSET. + +void +Gdb_index::set_pubnames_read(const Relobj* object, off_t offset) +{ + this->pubnames_object_ = object; + this->stmt_list_offset_ = offset; +} + +// Set the size of the .gdb_index section. + +void +Gdb_index::set_final_data_size() +{ + // Finalize the string pool. + this->stringpool_.set_string_offsets(); + + // Compute the total size of the CU vectors. + // For each CU vector, include one entry for the count at the + // beginning of the vector. + unsigned int cu_vector_count = this->cu_vector_list_.size(); + unsigned int cu_vector_size = 0; + this->cu_vector_offsets_ = new off_t[cu_vector_count]; + for (unsigned int i = 0; i < cu_vector_count; ++i) + { + Cu_vector* cu_vec = this->cu_vector_list_[i]; + cu_vector_offsets_[i] = cu_vector_size; + cu_vector_size += gdb_index_offset_size * (cu_vec->size() + 1); + } + + // Assign relative offsets to each portion of the index, + // and find the total size of the section. + section_size_type data_size = gdb_index_hdr_size; + data_size += this->comp_units_.size() * gdb_index_cu_size; + this->tu_offset_ = data_size; + data_size += this->type_units_.size() * gdb_index_tu_size; + this->addr_offset_ = data_size; + for (unsigned int i = 0; i < this->ranges_.size(); ++i) + data_size += this->ranges_[i].ranges->size() * gdb_index_addr_size; + this->symtab_offset_ = data_size; + data_size += this->gdb_symtab_->capacity() * gdb_index_sym_size; + this->cu_pool_offset_ = data_size; + data_size += cu_vector_size; + this->stringpool_offset_ = data_size; + data_size += this->stringpool_.get_strtab_size(); + + this->set_data_size(data_size); +} + +// Write the data to the file. + +void +Gdb_index::do_write(Output_file* of) +{ + const off_t off = this->offset(); + const off_t oview_size = this->data_size(); + unsigned char* const oview = of->get_output_view(off, oview_size); + unsigned char* pov = oview; + + // Write the file header. + // (1) Version number. + elfcpp::Swap<32, false>::writeval(pov, gdb_index_version); + pov += 4; + // (2) Offset of the CU list. + elfcpp::Swap<32, false>::writeval(pov, gdb_index_hdr_size); + pov += 4; + // (3) Offset of the types CU list. + elfcpp::Swap<32, false>::writeval(pov, this->tu_offset_); + pov += 4; + // (4) Offset of the address area. + elfcpp::Swap<32, false>::writeval(pov, this->addr_offset_); + pov += 4; + // (5) Offset of the symbol table. + elfcpp::Swap<32, false>::writeval(pov, this->symtab_offset_); + pov += 4; + // (6) Offset of the constant pool. + elfcpp::Swap<32, false>::writeval(pov, this->cu_pool_offset_); + pov += 4; + + gold_assert(pov - oview == gdb_index_hdr_size); + + // Write the CU list. + unsigned int comp_units_count = this->comp_units_.size(); + for (unsigned int i = 0; i < comp_units_count; ++i) + { + const Comp_unit& cu = this->comp_units_[i]; + elfcpp::Swap<64, false>::writeval(pov, cu.cu_offset); + elfcpp::Swap<64, false>::writeval(pov + 8, cu.cu_length); + pov += 16; + } + + gold_assert(pov - oview == this->tu_offset_); + + // Write the types CU list. + for (unsigned int i = 0; i < this->type_units_.size(); ++i) + { + const Type_unit& tu = this->type_units_[i]; + elfcpp::Swap<64, false>::writeval(pov, tu.tu_offset); + elfcpp::Swap<64, false>::writeval(pov + 8, tu.type_offset); + elfcpp::Swap<64, false>::writeval(pov + 16, tu.type_signature); + pov += 24; + } + + gold_assert(pov - oview == this->addr_offset_); + + // Write the address area. + for (unsigned int i = 0; i < this->ranges_.size(); ++i) + { + int cu_index = this->ranges_[i].cu_index; + // Translate negative indexes, which refer to a TU, to a + // logical index into a concatenated CU/TU list. + if (cu_index < 0) + cu_index = comp_units_count + (-1 - cu_index); + Relobj* object = this->ranges_[i].object; + const Dwarf_range_list& ranges = *this->ranges_[i].ranges; + for (unsigned int j = 0; j < ranges.size(); ++j) + { + const Dwarf_range_list::Range& range = ranges[j]; + uint64_t base = 0; + if (range.shndx > 0) + { + const Output_section* os = object->output_section(range.shndx); + base = (os->address() + + object->output_section_offset(range.shndx)); + } + elfcpp::Swap_aligned32<64, false>::writeval(pov, base + range.start); + elfcpp::Swap_aligned32<64, false>::writeval(pov + 8, + base + range.end); + elfcpp::Swap<32, false>::writeval(pov + 16, cu_index); + pov += 20; + } + } + + gold_assert(pov - oview == this->symtab_offset_); + + // Write the symbol table. + for (unsigned int i = 0; i < this->gdb_symtab_->capacity(); ++i) + { + const Gdb_symbol* sym = (*this->gdb_symtab_)[i]; + section_offset_type name_offset = 0; + unsigned int cu_vector_offset = 0; + if (sym != NULL) + { + name_offset = (this->stringpool_.get_offset_from_key(sym->name_key) + + this->stringpool_offset_ - this->cu_pool_offset_); + cu_vector_offset = this->cu_vector_offsets_[sym->cu_vector_index]; + } + elfcpp::Swap<32, false>::writeval(pov, name_offset); + elfcpp::Swap<32, false>::writeval(pov + 4, cu_vector_offset); + pov += 8; + } + + gold_assert(pov - oview == this->cu_pool_offset_); + + // Write the CU vectors into the constant pool. + for (unsigned int i = 0; i < this->cu_vector_list_.size(); ++i) + { + Cu_vector* cu_vec = this->cu_vector_list_[i]; + elfcpp::Swap<32, false>::writeval(pov, cu_vec->size()); + pov += 4; + for (unsigned int j = 0; j < cu_vec->size(); ++j) + { + int cu_index = (*cu_vec)[j]; + if (cu_index < 0) + cu_index = comp_units_count + (-1 - cu_index); + elfcpp::Swap<32, false>::writeval(pov, cu_index); + pov += 4; + } + } + + gold_assert(pov - oview == this->stringpool_offset_); + + // Write the strings into the constant pool. + this->stringpool_.write_to_buffer(pov, oview_size - this->stringpool_offset_); + + of->write_output_view(off, oview_size, oview); +} + +// Print usage statistics. +void +Gdb_index::print_stats() +{ + if (parameters->options().gdb_index()) + Gdb_index_info_reader::print_stats(); +} + +} // End namespace gold. diff --git a/binutils-2.25/gold/gdb-index.h b/binutils-2.25/gold/gdb-index.h new file mode 100644 index 00000000..5d9fe476 --- /dev/null +++ b/binutils-2.25/gold/gdb-index.h @@ -0,0 +1,263 @@ +// gdb-index.h -- generate .gdb_index section for fast debug lookup -*- C++ -*- + +// Copyright 2012 Free Software Foundation, Inc. +// Written by Cary Coutant . + +// 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 +#include + +#include "gold.h" +#include "output.h" +#include "mapfile.h" +#include "stringpool.h" + +#ifndef GOLD_GDB_INDEX_H +#define GOLD_GDB_INDEX_H + +namespace gold +{ + +class Output_section; +class Output_file; +class Mapfile; +template +class Sized_relobj; +class Dwarf_range_list; +template +class Gdb_hashtab; +class Gdb_index_info_reader; +class Dwarf_pubnames_table; + +// This class manages the .gdb_index section, which is a fast +// lookup table for DWARF information used by the gdb debugger. +// The format of this section is described in gdb/doc/gdb.texinfo. + +class Gdb_index : public Output_section_data +{ + public: + Gdb_index(Output_section* gdb_index_section); + + ~Gdb_index(); + + // Scan a .debug_info or .debug_types input section. + void scan_debug_info(bool is_type_unit, + Relobj* object, + const unsigned char* symbols, + off_t symbols_size, + unsigned int shndx, + unsigned int reloc_shndx, + unsigned int reloc_type); + + // Add a compilation unit. + int + add_comp_unit(off_t cu_offset, off_t cu_length) + { + this->comp_units_.push_back(Comp_unit(cu_offset, cu_length)); + return this->comp_units_.size() - 1; + } + + // Add a type unit. + int + add_type_unit(off_t tu_offset, off_t type_offset, uint64_t signature) + { + this->type_units_.push_back(Type_unit(tu_offset, type_offset, signature)); + return this->type_units_.size() - 1; + } + + // Add an address range. + void + add_address_range_list(Relobj* object, unsigned int cu_index, + Dwarf_range_list* ranges) + { + this->ranges_.push_back(Per_cu_range_list(object, cu_index, ranges)); + } + + // Add a symbol. + void + add_symbol(int cu_index, const char* sym_name); + + // Return the offset into the pubnames table for the cu at the given + // offset. + off_t + find_pubname_offset(off_t cu_offset); + + // Return the offset into the pubtypes table for the cu at the + // given offset. + off_t + find_pubtype_offset(off_t cu_offset); + + // Return TRUE if we have already processed the pubnames and types + // set for OBJECT of the CUs and TUS associated with the statement + // list at OFFSET. + bool + pubnames_read(const Relobj* object, off_t offset); + + // Record that we have already read the pubnames associated with + // OBJECT and OFFSET. + void + set_pubnames_read(const Relobj* object, off_t offset); + + // Return a pointer to the given table. + Dwarf_pubnames_table* + pubnames_table() + { return pubnames_table_; } + + Dwarf_pubnames_table* + pubtypes_table() + { return pubtypes_table_; } + + // Print usage statistics. + static void + print_stats(); + + protected: + // This is called to update the section size prior to assigning + // the address and file offset. + void + update_data_size() + { this->set_final_data_size(); } + + // Set the final data size. + void + set_final_data_size(); + + // Write the data to the file. + void + do_write(Output_file*); + + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _("** gdb_index")); } + + // Create a map from dies to pubnames. + Dwarf_pubnames_table* + map_pubtable_to_dies(unsigned int attr, + Gdb_index_info_reader* dwinfo, + Relobj* object, + const unsigned char* symbols, + off_t symbols_size); + + // Wrapper for map_pubtable_to_dies + void + map_pubnames_and_types_to_dies(Gdb_index_info_reader* dwinfo, + Relobj* object, + const unsigned char* symbols, + off_t symbols_size); + + private: + // An entry in the compilation unit list. + struct Comp_unit + { + Comp_unit(off_t off, off_t len) + : cu_offset(off), cu_length(len) + { } + uint64_t cu_offset; + uint64_t cu_length; + }; + + // An entry in the type unit list. + struct Type_unit + { + Type_unit(off_t off, off_t toff, uint64_t sig) + : tu_offset(off), type_offset(toff), type_signature(sig) + { } + uint64_t tu_offset; + uint64_t type_offset; + uint64_t type_signature; + }; + + // An entry in the address range list. + struct Per_cu_range_list + { + Per_cu_range_list(Relobj* obj, uint32_t index, Dwarf_range_list* r) + : object(obj), cu_index(index), ranges(r) + { } + Relobj* object; + uint32_t cu_index; + Dwarf_range_list* ranges; + }; + + // A symbol table entry. + struct Gdb_symbol + { + Stringpool::Key name_key; + unsigned int hashval; + unsigned int cu_vector_index; + + // Return the hash value. + unsigned int + hash() + { return this->hashval; } + + // Return true if this symbol is the same as SYMBOL. + bool + equal(Gdb_symbol* symbol) + { return this->name_key == symbol->name_key; } + }; + + typedef std::vector Cu_vector; + + typedef Unordered_map Pubname_offset_map; + Pubname_offset_map cu_pubname_map_; + Pubname_offset_map cu_pubtype_map_; + + // Scan the given pubtable and build a map of the various dies it + // refers to, so we can process the entries when we encounter the + // die. + void + map_pubtable_to_dies(Dwarf_pubnames_table* table, + Pubname_offset_map* map); + + // Tables to store the pubnames section of the current object. + Dwarf_pubnames_table* pubnames_table_; + Dwarf_pubnames_table* pubtypes_table_; + + // The .gdb_index section. + Output_section* gdb_index_section_; + // The list of DWARF compilation units. + std::vector comp_units_; + // The list of DWARF type units. + std::vector type_units_; + // The list of address ranges. + std::vector ranges_; + // The symbol table. + Gdb_hashtab* gdb_symtab_; + // The CU vector portion of the constant pool. + std::vector cu_vector_list_; + // An array to map from a CU vector index to an offset to the constant pool. + off_t* cu_vector_offsets_; + // The string portion of the constant pool. + Stringpool stringpool_; + // Offsets of the various pieces of the .gdb_index section. + off_t tu_offset_; + off_t addr_offset_; + off_t symtab_offset_; + off_t cu_pool_offset_; + off_t stringpool_offset_; + // Object, stmt list offset of the CUs and TUs associated with the + // last read pubnames and pubtypes sections. + const Relobj* pubnames_object_; + off_t stmt_list_offset_; +}; + +} // End namespace gold. + +#endif // !defined(GOLD_GDB_INDEX_H) diff --git a/binutils-2.25/gold/gold-threads.cc b/binutils-2.25/gold/gold-threads.cc new file mode 100644 index 00000000..2cb293e3 --- /dev/null +++ b/binutils-2.25/gold/gold-threads.cc @@ -0,0 +1,450 @@ +// gold-threads.cc -- thread support for gold + +// Copyright 2006, 2007, 2008, 2009, 2010, 2013 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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 + +#ifdef ENABLE_THREADS +#include +#endif + +#include "options.h" +#include "parameters.h" +#include "gold-threads.h" + +namespace gold +{ + +class Condvar_impl_nothreads; + +// The non-threaded version of Lock_impl. + +class Lock_impl_nothreads : public Lock_impl +{ + public: + Lock_impl_nothreads() + : acquired_(false) + { } + + ~Lock_impl_nothreads() + { gold_assert(!this->acquired_); } + + void + acquire() + { + gold_assert(!this->acquired_); + this->acquired_ = true; + } + + void + release() + { + gold_assert(this->acquired_); + this->acquired_ = false; + } + + private: + friend class Condvar_impl_nothreads; + + bool acquired_; +}; + +#ifdef ENABLE_THREADS + +class Condvar_impl_threads; + +// The threaded version of Lock_impl. + +class Lock_impl_threads : public Lock_impl +{ + public: + Lock_impl_threads(); + ~Lock_impl_threads(); + + void acquire(); + + void release(); + +private: + // This class can not be copied. + Lock_impl_threads(const Lock_impl_threads&); + Lock_impl_threads& operator=(const Lock_impl_threads&); + + friend class Condvar_impl_threads; + + pthread_mutex_t mutex_; +}; + +Lock_impl_threads::Lock_impl_threads() +{ + pthread_mutexattr_t attr; + int err = pthread_mutexattr_init(&attr); + if (err != 0) + gold_fatal(_("pthead_mutextattr_init failed: %s"), strerror(err)); +#ifdef PTHREAD_MUTEX_ADAPTIVE_NP + err = pthread_mutextattr_settype(&attr, PTHREAD_MUTEX_ADAPTIVE_NP); + if (err != 0) + gold_fatal(_("pthread_mutextattr_settype failed: %s"), strerror(err)); +#endif + + err = pthread_mutex_init(&this->mutex_, &attr); + if (err != 0) + gold_fatal(_("pthread_mutex_init failed: %s"), strerror(err)); + + err = pthread_mutexattr_destroy(&attr); + if (err != 0) + gold_fatal(_("pthread_mutexattr_destroy failed: %s"), strerror(err)); +} + +Lock_impl_threads::~Lock_impl_threads() +{ + int err = pthread_mutex_destroy(&this->mutex_); + if (err != 0) + gold_fatal(_("pthread_mutex_destroy failed: %s"), strerror(err)); +} + +void +Lock_impl_threads::acquire() +{ + int err = pthread_mutex_lock(&this->mutex_); + if (err != 0) + gold_fatal(_("pthread_mutex_lock failed: %s"), strerror(err)); +} + +void +Lock_impl_threads::release() +{ + int err = pthread_mutex_unlock(&this->mutex_); + if (err != 0) + gold_fatal(_("pthread_mutex_unlock failed: %s"), strerror(err)); +} + +#endif // defined(ENABLE_THREADS) + +// Class Lock. + +Lock::Lock() +{ + if (!parameters->options().threads()) + this->lock_ = new Lock_impl_nothreads; + else + { +#ifdef ENABLE_THREADS + this->lock_ = new Lock_impl_threads; +#else + gold_unreachable(); +#endif + } +} + +Lock::~Lock() +{ + delete this->lock_; +} + +// The non-threaded version of Condvar_impl. + +class Condvar_impl_nothreads : public Condvar_impl +{ + public: + Condvar_impl_nothreads() + { } + + ~Condvar_impl_nothreads() + { } + + void + wait(Lock_impl* li) + { gold_assert(static_cast(li)->acquired_); } + + void + signal() + { } + + void + broadcast() + { } +}; + +#ifdef ENABLE_THREADS + +// The threaded version of Condvar_impl. + +class Condvar_impl_threads : public Condvar_impl +{ + public: + Condvar_impl_threads(); + ~Condvar_impl_threads(); + + void + wait(Lock_impl*); + + void + signal(); + + void + broadcast(); + + private: + // This class can not be copied. + Condvar_impl_threads(const Condvar_impl_threads&); + Condvar_impl_threads& operator=(const Condvar_impl_threads&); + + pthread_cond_t cond_; +}; + +Condvar_impl_threads::Condvar_impl_threads() +{ + int err = pthread_cond_init(&this->cond_, NULL); + if (err != 0) + gold_fatal(_("pthread_cond_init failed: %s"), strerror(err)); +} + +Condvar_impl_threads::~Condvar_impl_threads() +{ + int err = pthread_cond_destroy(&this->cond_); + if (err != 0) + gold_fatal(_("pthread_cond_destroy failed: %s"), strerror(err)); +} + +void +Condvar_impl_threads::wait(Lock_impl* li) +{ + Lock_impl_threads* lit = static_cast(li); + int err = pthread_cond_wait(&this->cond_, &lit->mutex_); + if (err != 0) + gold_fatal(_("pthread_cond_wait failed: %s"), strerror(err)); +} + +void +Condvar_impl_threads::signal() +{ + int err = pthread_cond_signal(&this->cond_); + if (err != 0) + gold_fatal(_("pthread_cond_signal failed: %s"), strerror(err)); +} + +void +Condvar_impl_threads::broadcast() +{ + int err = pthread_cond_broadcast(&this->cond_); + if (err != 0) + gold_fatal(_("pthread_cond_broadcast failed: %s"), strerror(err)); +} + +#endif // defined(ENABLE_THREADS) + +// Methods for Condvar class. + +Condvar::Condvar(Lock& lock) + : lock_(lock) +{ + if (!parameters->options().threads()) + this->condvar_ = new Condvar_impl_nothreads; + else + { +#ifdef ENABLE_THREADS + this->condvar_ = new Condvar_impl_threads; +#else + gold_unreachable(); +#endif + } +} + +Condvar::~Condvar() +{ + delete this->condvar_; +} + +#ifdef ENABLE_THREADS + +// Class Once_initialize. This exists to hold a pthread_once_t +// structure for Once. + +class Once_initialize +{ + public: + Once_initialize() + : once_(PTHREAD_ONCE_INIT) + { } + + // Return a pointer to the pthread_once_t variable. + pthread_once_t* + once_control() + { return &this->once_; } + + private: + pthread_once_t once_; +}; + +#endif // defined(ENABLE_THREADS) + +#ifdef ENABLE_THREADS + +// A single lock which controls access to once_pointer. This is used +// because we can't pass parameters to functions passed to +// pthread_once. + +static pthread_mutex_t once_pointer_control = PTHREAD_MUTEX_INITIALIZER; + +// A pointer to Once structure we want to run. Access to this is +// controlled by once_pointer_control. + +static Once* once_pointer; + +// The argument to pass to the Once structure. Access to this is +// controlled by once_pointer_control. + +static void* once_arg; + +// A routine passed to pthread_once which runs the Once pointer. + +extern "C" +{ + +static void +c_run_once(void) +{ + once_pointer->internal_run(once_arg); +} + +} + +#endif // defined(ENABLE_THREADS) + +// Class Once. + +Once::Once() + : was_run_(false) +#if defined(ENABLE_THREADS) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) + , was_run_lock_(0) +#endif +{ +#ifndef ENABLE_THREADS + this->once_ = NULL; +#else + this->once_ = new Once_initialize(); +#endif +} + +// Run the function once. + +void +Once::run_once(void* arg) +{ +#ifndef ENABLE_THREADS + + // If there is no threads support, we don't need to use pthread_once. + if (!this->was_run_) + this->internal_run(arg); + +#else // defined(ENABLE_THREADS) + + if (parameters->options_valid() && !parameters->options().threads()) + { + // If we are not using threads, we don't need to lock. + if (!this->was_run_) + this->internal_run(arg); + return; + } + + // If we have the sync builtins, use them to skip the lock if the + // value has already been initialized. +#ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 + while (true) + { + if (__sync_bool_compare_and_swap(&this->was_run_lock_, 0, 1)) + break; + } + bool was_run = this->was_run_; + while (true) + { + if (__sync_bool_compare_and_swap(&this->was_run_lock_, 1, 0)) + break; + } + if (was_run) + return; +#endif + + // Since we can't pass parameters to routines called by + // pthread_once, we use a static variable: once_pointer. This in + // turns means that we need to use a mutex to control access to + // once_pointer. + + int err = pthread_mutex_lock(&once_pointer_control); + if (err != 0) + gold_fatal(_("pthread_mutex_lock failed: %s"), strerror(err)); + + once_pointer = this; + once_arg = arg; + + err = pthread_once(this->once_->once_control(), c_run_once); + if (err != 0) + gold_fatal(_("pthread_once failed: %s"), strerror(err)); + + once_pointer = NULL; + once_arg = NULL; + + err = pthread_mutex_unlock(&once_pointer_control); + if (err != 0) + gold_fatal(_("pthread_mutex_unlock failed: %s"), strerror(err)); + +#endif // defined(ENABLE_THREADS) +} + +// Actually run the function in the child class. This function will +// be run only once. + +void +Once::internal_run(void* arg) +{ + this->do_run_once(arg); + this->was_run_ = true; +} + +// Class Initialize_lock. + +// Initialize the lock. + +bool +Initialize_lock::initialize() +{ + // We can't initialize the lock until we have read the options. + if (!parameters->options_valid()) + return false; + else + { + this->run_once(NULL); + return true; + } +} + +// Initialize the lock exactly once. + +void +Initialize_lock::do_run_once(void*) +{ + *this->pplock_ = new Lock(); +} + +} // End namespace gold. diff --git a/binutils-2.25/gold/gold-threads.h b/binutils-2.25/gold/gold-threads.h new file mode 100644 index 00000000..5751f62b --- /dev/null +++ b/binutils-2.25/gold/gold-threads.h @@ -0,0 +1,267 @@ +// gold-threads.h -- thread support for gold -*- C++ -*- + +// Copyright 2006, 2007, 2008, 2009, 2010, 2013 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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. + +// gold can be configured to support threads. If threads are +// supported, the user can specify at runtime whether or not to +// support them. This provides an interface to manage locking +// accordingly. + +// Lock +// A simple lock class. + +#ifndef GOLD_THREADS_H +#define GOLD_THREADS_H + +namespace gold +{ + +class Condvar; +class Once_initialize; +class Initialize_lock_once; + +// The interface for the implementation of a Lock. + +class Lock_impl +{ + public: + Lock_impl() + { } + + virtual + ~Lock_impl() + { } + + virtual void + acquire() = 0; + + virtual void + release() = 0; +}; + +// A simple lock class. + +class Lock +{ + public: + Lock(); + + ~Lock(); + + // Acquire the lock. + void + acquire() + { this->lock_->acquire(); } + + // Release the lock. + void + release() + { this->lock_->release(); } + + private: + // This class can not be copied. + Lock(const Lock&); + Lock& operator=(const Lock&); + + friend class Condvar; + Lock_impl* + get_impl() const + { return this->lock_; } + + Lock_impl* lock_; +}; + +// RAII for Lock. + +class Hold_lock +{ + public: + Hold_lock(Lock& lock) + : lock_(lock) + { this->lock_.acquire(); } + + ~Hold_lock() + { this->lock_.release(); } + + private: + // This class can not be copied. + Hold_lock(const Hold_lock&); + Hold_lock& operator=(const Hold_lock&); + + Lock& lock_; +}; + +class Hold_optional_lock +{ + public: + Hold_optional_lock(Lock* lock) + : lock_(lock) + { + if (this->lock_ != NULL) + this->lock_->acquire(); + } + + ~Hold_optional_lock() + { + if (this->lock_ != NULL) + this->lock_->release(); + } + + private: + Hold_optional_lock(const Hold_optional_lock&); + Hold_optional_lock& operator=(const Hold_optional_lock&); + + Lock* lock_; +}; + +// The interface for the implementation of a condition variable. + +class Condvar_impl +{ + public: + Condvar_impl() + { } + + virtual + ~Condvar_impl() + { } + + virtual void + wait(Lock_impl*) = 0; + + virtual void + signal() = 0; + + virtual void + broadcast() = 0; +}; + +// A simple condition variable class. It is always associated with a +// specific lock. + +class Condvar +{ + public: + Condvar(Lock& lock); + ~Condvar(); + + // Wait for the condition variable to be signalled. This should + // only be called when the lock is held. + void + wait() + { this->condvar_->wait(this->lock_.get_impl()); } + + // Signal the condition variable--wake up at least one thread + // waiting on the condition variable. This should only be called + // when the lock is held. + void + signal() + { this->condvar_->signal(); } + + // Broadcast the condition variable--wake up all threads waiting on + // the condition variable. This should only be called when the lock + // is held. + void + broadcast() + { this->condvar_->broadcast(); } + + private: + // This class can not be copied. + Condvar(const Condvar&); + Condvar& operator=(const Condvar&); + + Lock& lock_; + Condvar_impl* condvar_; +}; + +// A class used to do something once. This is an abstract parent +// class; any actual use will involve a child of this. + +class Once +{ + public: + Once(); + + virtual + ~Once() + { } + + // Call this function to do whatever it is. We pass an argument + // even though you have to use a child class because in some uses + // setting the argument would itself require a Once class. + void + run_once(void* arg); + + // This is an internal function, which must be public because it is + // run by an extern "C" function called via pthread_once. + void + internal_run(void* arg); + + protected: + // This must be implemented by the child class. + virtual void + do_run_once(void* arg) = 0; + + private: + // True if we have already run the function. + bool was_run_; +#if defined(ENABLE_THREADS) && defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) + // Internal compare-and-swap lock on was_run_; + uint32_t was_run_lock_; +#endif + // The lock to run the function only once. + Once_initialize* once_; +}; + +// A class used to initialize a lock exactly once, after the options +// have been read. This is needed because the implementation of locks +// depends on whether we've seen the --threads option. Before the +// options have been read, we know we are single-threaded, so we can +// get by without using a lock. This class should be an instance +// variable of the class which has a lock which needs to be +// initialized. + +class Initialize_lock : public Once +{ + public: + // The class which uses this will have a pointer to a lock. This + // must be constructed with a pointer to that pointer. + Initialize_lock(Lock** pplock) + : pplock_(pplock) + { } + + // Initialize the lock. Return true if the lock is now initialized, + // false if it is not (because the options have not yet been read). + bool + initialize(); + + protected: + void + do_run_once(void*); + + private: + // A pointer to the lock pointer which must be initialized. + Lock** const pplock_; +}; + +} // End namespace gold. + +#endif // !defined(GOLD_THREADS_H) diff --git a/binutils-2.25/gold/gold.cc b/binutils-2.25/gold/gold.cc new file mode 100644 index 00000000..4de9289b --- /dev/null +++ b/binutils-2.25/gold/gold.cc @@ -0,0 +1,888 @@ +// gold.cc -- main linker functions + +// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012 +// Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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 +#include +#include +#include +#include +#include "libiberty.h" + +#include "options.h" +#include "target-select.h" +#include "debug.h" +#include "workqueue.h" +#include "dirsearch.h" +#include "readsyms.h" +#include "symtab.h" +#include "common.h" +#include "object.h" +#include "layout.h" +#include "reloc.h" +#include "defstd.h" +#include "plugin.h" +#include "gc.h" +#include "icf.h" +#include "incremental.h" +#include "timer.h" + +namespace gold +{ + +class Object; + +const char* program_name; + +static Task* +process_incremental_input(Incremental_binary*, unsigned int, Input_objects*, + Symbol_table*, Layout*, Dirsearch*, Mapfile*, + Task_token*, Task_token*); + +void +gold_exit(Exit_status status) +{ + if (parameters != NULL + && parameters->options_valid() + && parameters->options().has_plugins()) + parameters->options().plugins()->cleanup(); + if (status != GOLD_OK && parameters != NULL && parameters->options_valid()) + unlink_if_ordinary(parameters->options().output_file_name()); + exit(status); +} + +void +gold_nomem() +{ + // We are out of memory, so try hard to print a reasonable message. + // Note that we don't try to translate this message, since the + // translation process itself will require memory. + + // LEN only exists to avoid a pointless warning when write is + // declared with warn_use_result, as when compiling with + // -D_USE_FORTIFY on GNU/Linux. Casting to void does not appear to + // work, at least not with gcc 4.3.0. + + ssize_t len = write(2, program_name, strlen(program_name)); + if (len >= 0) + { + const char* const s = ": out of memory\n"; + len = write(2, s, strlen(s)); + } + gold_exit(GOLD_ERR); +} + +// Handle an unreachable case. + +void +do_gold_unreachable(const char* filename, int lineno, const char* function) +{ + fprintf(stderr, _("%s: internal error in %s, at %s:%d\n"), + program_name, function, filename, lineno); + gold_exit(GOLD_ERR); +} + +// This class arranges to run the functions done in the middle of the +// link. It is just a closure. + +class Middle_runner : public Task_function_runner +{ + public: + Middle_runner(const General_options& options, + const Input_objects* input_objects, + Symbol_table* symtab, + Layout* layout, Mapfile* mapfile) + : options_(options), input_objects_(input_objects), symtab_(symtab), + layout_(layout), mapfile_(mapfile) + { } + + void + run(Workqueue*, const Task*); + + private: + const General_options& options_; + const Input_objects* input_objects_; + Symbol_table* symtab_; + Layout* layout_; + Mapfile* mapfile_; +}; + +void +Middle_runner::run(Workqueue* workqueue, const Task* task) +{ + queue_middle_tasks(this->options_, task, this->input_objects_, this->symtab_, + this->layout_, workqueue, this->mapfile_); +} + +// This class arranges the tasks to process the relocs for garbage collection. + +class Gc_runner : public Task_function_runner +{ + public: + Gc_runner(const General_options& options, + const Input_objects* input_objects, + Symbol_table* symtab, + Layout* layout, Mapfile* mapfile) + : options_(options), input_objects_(input_objects), symtab_(symtab), + layout_(layout), mapfile_(mapfile) + { } + + void + run(Workqueue*, const Task*); + + private: + const General_options& options_; + const Input_objects* input_objects_; + Symbol_table* symtab_; + Layout* layout_; + Mapfile* mapfile_; +}; + +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 up the initial set of tasks for this link job. + +void +queue_initial_tasks(const General_options& options, + Dirsearch& search_path, + const Command_line& cmdline, + Workqueue* workqueue, Input_objects* input_objects, + Symbol_table* symtab, Layout* layout, Mapfile* mapfile) +{ + if (cmdline.begin() == cmdline.end()) + { + bool is_ok = false; + if (options.printed_version()) + is_ok = true; + if (options.print_output_format()) + { + print_output_format(); + is_ok = true; + } + if (is_ok) + gold_exit(GOLD_OK); + gold_fatal(_("no input files")); + } + + int thread_count = options.thread_count_initial(); + if (thread_count == 0) + thread_count = cmdline.number_of_input_files(); + workqueue->set_thread_count(thread_count); + + // For incremental links, the base output file. + Incremental_binary* ibase = NULL; + + if (parameters->incremental_update()) + { + Output_file* of = new Output_file(options.output_file_name()); + if (of->open_base_file(options.incremental_base(), true)) + { + ibase = open_incremental_binary(of); + if (ibase != NULL + && ibase->check_inputs(cmdline, layout->incremental_inputs())) + ibase->init_layout(layout); + else + { + delete ibase; + ibase = NULL; + of->close(); + } + } + if (ibase == NULL) + { + if (set_parameters_incremental_full()) + gold_info(_("linking with --incremental-full")); + else + gold_fallback(_("restart link with --incremental-full")); + } + } + + // Read the input files. We have to add the symbols to the symbol + // table in order. We do this by creating a separate blocker for + // each input file. We associate the blocker with the following + // input file, to give us a convenient place to delete it. + Task_token* this_blocker = NULL; + if (ibase == NULL) + { + // Normal link. Queue a Read_symbols task for each input file + // on the command line. + for (Command_line::const_iterator p = cmdline.begin(); + p != cmdline.end(); + ++p) + { + Task_token* next_blocker = new Task_token(true); + next_blocker->add_blocker(); + workqueue->queue(new Read_symbols(input_objects, symtab, layout, + &search_path, 0, mapfile, &*p, NULL, + NULL, this_blocker, next_blocker)); + this_blocker = next_blocker; + } + } + else + { + // Incremental update link. Process the list of input files + // stored in the base file, and queue a task for each file: + // a Read_symbols task for a changed file, and an Add_symbols task + // for an unchanged file. We need to mark all the space used by + // unchanged files before we can start any tasks running. + unsigned int input_file_count = ibase->input_file_count(); + std::vector tasks; + tasks.reserve(input_file_count); + for (unsigned int i = 0; i < input_file_count; ++i) + { + Task_token* next_blocker = new Task_token(true); + next_blocker->add_blocker(); + Task* t = process_incremental_input(ibase, i, input_objects, symtab, + layout, &search_path, mapfile, + this_blocker, next_blocker); + tasks.push_back(t); + this_blocker = next_blocker; + } + // Now we can queue the tasks. + for (unsigned int i = 0; i < tasks.size(); i++) + workqueue->queue(tasks[i]); + } + + if (options.has_plugins()) + { + Task_token* next_blocker = new Task_token(true); + next_blocker->add_blocker(); + workqueue->queue(new Plugin_hook(options, input_objects, symtab, layout, + &search_path, mapfile, this_blocker, + next_blocker)); + this_blocker = next_blocker; + } + + if (options.relocatable() + && (options.gc_sections() || options.icf_enabled())) + gold_error(_("cannot mix -r with --gc-sections or --icf")); + + if (options.gc_sections() || options.icf_enabled()) + { + workqueue->queue(new Task_function(new Gc_runner(options, + input_objects, + 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")); + } +} + +// Process an incremental input file: if it is unchanged from the previous +// link, return a task to add its symbols from the base file's incremental +// info; if it has changed, return a normal Read_symbols task. We create a +// task for every input file, if only to report the file for rebuilding the +// incremental info. + +static Task* +process_incremental_input(Incremental_binary* ibase, + unsigned int input_file_index, + Input_objects* input_objects, + Symbol_table* symtab, + Layout* layout, + Dirsearch* search_path, + Mapfile* mapfile, + Task_token* this_blocker, + Task_token* next_blocker) +{ + const Incremental_binary::Input_reader* input_reader = + ibase->get_input_reader(input_file_index); + Incremental_input_type input_type = input_reader->type(); + + // Get the input argument corresponding to this input file, matching on + // the argument serial number. If the input file cannot be matched + // to an existing input argument, synthesize a new one. + const Input_argument* input_argument = + ibase->get_input_argument(input_file_index); + if (input_argument == NULL) + { + Input_file_argument file(input_reader->filename(), + Input_file_argument::INPUT_FILE_TYPE_FILE, + "", false, parameters->options()); + Input_argument* arg = new Input_argument(file); + arg->set_script_info(ibase->get_script_info(input_file_index)); + input_argument = arg; + } + + gold_debug(DEBUG_INCREMENTAL, "Incremental object: %s, type %d", + input_reader->filename(), input_type); + + if (input_type == INCREMENTAL_INPUT_SCRIPT) + { + // Incremental_binary::check_inputs should have cancelled the + // incremental update if the script has changed. + gold_assert(!ibase->file_has_changed(input_file_index)); + return new Check_script(layout, ibase, input_file_index, input_reader, + this_blocker, next_blocker); + } + + if (input_type == INCREMENTAL_INPUT_ARCHIVE) + { + Incremental_library* lib = ibase->get_library(input_file_index); + gold_assert(lib != NULL); + if (lib->filename() == "/group/" + || !ibase->file_has_changed(input_file_index)) + { + // Queue a task to check that no references have been added to any + // of the library's unused symbols. + return new Check_library(symtab, layout, ibase, input_file_index, + input_reader, this_blocker, next_blocker); + } + else + { + // Queue a Read_symbols task to process the archive normally. + return new Read_symbols(input_objects, symtab, layout, search_path, + 0, mapfile, input_argument, NULL, NULL, + this_blocker, next_blocker); + } + } + + if (input_type == INCREMENTAL_INPUT_ARCHIVE_MEMBER) + { + // For archive members, check the timestamp of the containing archive. + Incremental_library* lib = ibase->get_library(input_file_index); + gold_assert(lib != NULL); + // Process members of a --start-lib/--end-lib group as normal objects. + if (lib->filename() != "/group/") + { + if (ibase->file_has_changed(lib->input_file_index())) + { + return new Read_member(input_objects, symtab, layout, mapfile, + input_reader, this_blocker, next_blocker); + } + else + { + // The previous contributions from this file will be kept. + // Mark the pieces of output sections contributed by this + // object. + ibase->reserve_layout(input_file_index); + Object* obj = make_sized_incremental_object(ibase, + input_file_index, + input_type, + input_reader); + return new Add_symbols(input_objects, symtab, layout, + search_path, 0, mapfile, input_argument, + obj, lib, NULL, this_blocker, + next_blocker); + } + } + } + + // Normal object file or shared library. Check if the file has changed + // since the last incremental link. + if (ibase->file_has_changed(input_file_index)) + { + return new Read_symbols(input_objects, symtab, layout, search_path, 0, + mapfile, input_argument, NULL, NULL, + this_blocker, next_blocker); + } + else + { + // The previous contributions from this file will be kept. + // Mark the pieces of output sections contributed by this object. + ibase->reserve_layout(input_file_index); + Object* obj = make_sized_incremental_object(ibase, + input_file_index, + input_type, + input_reader); + return new Add_symbols(input_objects, symtab, layout, search_path, 0, + mapfile, input_argument, obj, NULL, NULL, + this_blocker, next_blocker); + } +} + +// Queue up a set of tasks to be done before queueing the middle set +// of tasks. This is only necessary when garbage collection +// (--gc-sections) of unused sections is desired. The relocs are read +// and processed here early to determine the garbage sections before the +// relocs can be scanned in later tasks. + +void +queue_middle_gc_tasks(const General_options& options, + const Task* , + const Input_objects* input_objects, + Symbol_table* symtab, + Layout* layout, + Workqueue* workqueue, + Mapfile* mapfile) +{ + // Read_relocs for all the objects must be done and processed to find + // unused sections before any scanning of the relocs can take place. + Task_token* this_blocker = NULL; + for (Input_objects::Relobj_iterator p = input_objects->relobj_begin(); + 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, + next_blocker)); + this_blocker = next_blocker; + } + + // If we are given only archives in input, we have no regular + // objects and THIS_BLOCKER is NULL here. Create a dummy + // blocker here so that we can run the middle tasks immediately. + if (this_blocker == NULL) + { + gold_assert(input_objects->number_of_relobjs() == 0); + this_blocker = new Task_token(true); + } + + workqueue->queue(new Task_function(new Middle_runner(options, + input_objects, + symtab, + layout, + mapfile), + this_blocker, + "Task_function Middle_runner")); +} + +// Queue up the middle set of tasks. These are the tasks which run +// after all the input objects have been found and all the symbols +// have been read, but before we lay out the output file. + +void +queue_middle_tasks(const General_options& options, + const Task* task, + const Input_objects* input_objects, + Symbol_table* symtab, + Layout* layout, + Workqueue* workqueue, + Mapfile* mapfile) +{ + Timer* timer = parameters->timer(); + if (timer != NULL) + timer->stamp(0); + + // Add any symbols named with -u options to the symbol table. + 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 + // objects. + if (parameters->options().gc_sections()) + { + // Find the start symbol if any. + Symbol* sym = symtab->lookup(parameters->entry()); + if (sym != NULL) + symtab->gc_mark_symbol(sym); + sym = symtab->lookup(parameters->options().init()); + if (sym != NULL && sym->is_defined() && !sym->is_from_dynobj()) + symtab->gc_mark_symbol(sym); + sym = symtab->lookup(parameters->options().fini()); + if (sym != NULL && sym->is_defined() && !sym->is_from_dynobj()) + symtab->gc_mark_symbol(sym); + // Symbols named with -u should not be considered garbage. + symtab->gc_mark_undef_symbols(layout); + gold_assert(symtab->gc() != NULL); + // Do a transitive closure on all references to determine the worklist. + 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 + // 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, or when certain input + // sections have to be mapped to unique segments, Object::layout + // is called twice. It is called the first time when symbols + // are added. + if (parameters->options().gc_sections() + || parameters->options().icf_enabled() + || layout->is_unique_segment_for_sections_specified()) + { + for (Input_objects::Relobj_iterator p = input_objects->relobj_begin(); + p != input_objects->relobj_end(); + ++p) + { + Task_lock_obj tlo(task, *p); + (*p)->layout(symtab, layout, NULL); + } + } + + // Layout deferred objects due to plugins. + if (parameters->options().has_plugins()) + { + Plugin_manager* plugins = parameters->options().plugins(); + gold_assert(plugins != NULL); + plugins->layout_deferred_objects(); + } + + /* If plugins have specified a section order, re-arrange input sections + according to a specified section order. If --section-ordering-file is + also specified, do not do anything here. */ + if (parameters->options().has_plugins() + && layout->is_section_ordering_specified() + && !parameters->options().section_ordering_file ()) + { + 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()); + } + + 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); + } + } + } + + // We have to support the case of not seeing any input objects, and + // generate an empty file. Existing builds depend on being able to + // pass an empty archive to the linker and get an empty object file + // out. In order to do this we need to use a default target. + if (input_objects->number_of_input_objects() == 0 + && layout->incremental_base() == NULL) + parameters_force_valid_target(); + + int thread_count = options.thread_count_middle(); + if (thread_count == 0) + thread_count = std::max(2, input_objects->number_of_input_objects()); + workqueue->set_thread_count(thread_count); + + // Now we have seen all the input files. + const bool doing_static_link = + (!input_objects->any_dynamic() + && !parameters->options().output_is_position_independent()); + set_parameters_doing_static_link(doing_static_link); + if (!doing_static_link && options.is_static()) + { + // We print out just the first .so we see; there may be others. + gold_assert(input_objects->dynobj_begin() != input_objects->dynobj_end()); + gold_error(_("cannot mix -static with dynamic object %s"), + (*input_objects->dynobj_begin())->name().c_str()); + } + if (!doing_static_link && parameters->options().relocatable()) + gold_fatal(_("cannot mix -r with dynamic object %s"), + (*input_objects->dynobj_begin())->name().c_str()); + if (!doing_static_link + && options.oformat_enum() != General_options::OBJECT_FORMAT_ELF) + gold_fatal(_("cannot use non-ELF output format with dynamic object %s"), + (*input_objects->dynobj_begin())->name().c_str()); + + if (parameters->options().relocatable()) + { + Input_objects::Relobj_iterator p = input_objects->relobj_begin(); + if (p != input_objects->relobj_end()) + { + bool uses_split_stack = (*p)->uses_split_stack(); + for (++p; p != input_objects->relobj_end(); ++p) + { + if ((*p)->uses_split_stack() != uses_split_stack) + gold_fatal(_("cannot mix split-stack '%s' and " + "non-split-stack '%s' when using -r"), + (*input_objects->relobj_begin())->name().c_str(), + (*p)->name().c_str()); + } + } + } + + // For incremental updates, record the existing GOT and PLT entries, + // and the COPY relocations. + if (parameters->incremental_update()) + { + Incremental_binary* ibase = layout->incremental_base(); + ibase->process_got_plt(symtab, layout); + ibase->emit_copy_relocs(symtab); + } + + if (is_debugging_enabled(DEBUG_SCRIPT)) + layout->script_options()->print(stderr); + + // For each dynamic object, record whether we've seen all the + // dynamic objects that it depends upon. + input_objects->check_dynamic_dependencies(); + + // Do the --no-undefined-version check. + if (!parameters->options().undefined_version()) + { + Script_options* so = layout->script_options(); + so->version_script_info()->check_unmatched_names(symtab); + } + + // Create any automatic note sections. + layout->create_notes(); + + // Create any output sections required by any linker script. + layout->create_script_sections(); + + // Define some sections and symbols needed for a dynamic link. This + // handles some cases we want to see before we read the relocs. + layout->create_initial_dynamic_sections(symtab); + + // Define symbols from any linker scripts. + layout->define_script_symbols(symtab); + + // TODO(csilvers): figure out a more principled way to get the target + Target* target = const_cast(¶meters->target()); + + // Attach sections to segments. + layout->attach_sections_to_segments(target); + + if (!parameters->options().relocatable()) + { + // Predefine standard symbols. + define_standard_symbols(symtab, layout); + + // Define __start and __stop symbols for output sections where + // appropriate. + layout->define_section_symbols(symtab); + + // Define target-specific symbols. + target->define_standard_symbols(symtab, layout); + } + + // Make sure we have symbols for any required group signatures. + layout->define_group_signatures(symtab); + + Task_token* this_blocker = NULL; + + // Allocate common symbols. We use a blocker to run this before the + // Scan_relocs tasks, because it writes to the symbol table just as + // they do. + if (parameters->options().define_common()) + { + this_blocker = new Task_token(true); + this_blocker->add_blocker(); + workqueue->queue(new Allocate_commons_task(symtab, layout, mapfile, + this_blocker)); + } + + // If doing garbage collection, the relocations have already been read. + // Otherwise, read and scan the relocations. + 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_token* next_blocker = new Task_token(true); + next_blocker->add_blocker(); + workqueue->queue(new Scan_relocs(symtab, layout, *p, + (*p)->get_relocs_data(), + this_blocker, next_blocker)); + this_blocker = next_blocker; + } + } + else + { + // Read the relocations of the input files. We do this to find + // which symbols are used by relocations which require a GOT and/or + // a PLT entry, or a COPY reloc. When we implement garbage + // collection we will do it here by reading the relocations in a + // breadth first search by references. + // + // We could also read the relocations during the first pass, and + // mark symbols at that time. That is how the old GNU linker works. + // Doing that is more complex, since we may later decide to discard + // 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) + { + Task_token* next_blocker = new Task_token(true); + next_blocker->add_blocker(); + workqueue->queue(new Read_relocs(symtab, layout, *p, this_blocker, + next_blocker)); + this_blocker = next_blocker; + } + } + + if (this_blocker == NULL) + { + if (input_objects->number_of_relobjs() == 0) + { + // If we are given only archives in input, we have no regular + // objects and THIS_BLOCKER is NULL here. Create a dummy + // blocker here so that we can run the layout task immediately. + this_blocker = new Task_token(true); + } + 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 + // continuing if that happens. + gold_assert(parameters->errors()->error_count() > 0); + gold_exit(GOLD_ERR); + } + } + + // When all those tasks are complete, we can start laying out the + // output file. + workqueue->queue(new Task_function(new Layout_task_runner(options, + input_objects, + symtab, + target, + layout, + mapfile), + this_blocker, + "Task_function Layout_task_runner")); +} + +// Queue up the final set of tasks. This is called at the end of +// Layout_task. + +void +queue_final_tasks(const General_options& options, + const Input_objects* input_objects, + const Symbol_table* symtab, + Layout* layout, + Workqueue* workqueue, + Output_file* of) +{ + Timer* timer = parameters->timer(); + if (timer != NULL) + timer->stamp(1); + + int thread_count = options.thread_count_final(); + if (thread_count == 0) + thread_count = std::max(2, input_objects->number_of_input_objects()); + workqueue->set_thread_count(thread_count); + + bool any_postprocessing_sections = layout->any_postprocessing_sections(); + + // Use a blocker to wait until all the input sections have been + // written out. + Task_token* input_sections_blocker = NULL; + if (!any_postprocessing_sections) + { + input_sections_blocker = new Task_token(true); + input_sections_blocker->add_blockers(input_objects->number_of_relobjs()); + } + + // Use a blocker to block any objects which have to wait for the + // output sections to complete before they can apply relocations. + Task_token* output_sections_blocker = new Task_token(true); + output_sections_blocker->add_blocker(); + + // Use a blocker to block the final cleanup task. + Task_token* final_blocker = new Task_token(true); + // Write_symbols_task, Write_sections_task, Write_data_task, + // Relocate_tasks. + final_blocker->add_blockers(3); + final_blocker->add_blockers(input_objects->number_of_relobjs()); + if (!any_postprocessing_sections) + final_blocker->add_blocker(); + + // Queue a task to write out the symbol table. + workqueue->queue(new Write_symbols_task(layout, + symtab, + input_objects, + layout->sympool(), + layout->dynpool(), + of, + final_blocker)); + + // Queue a task to write out the output sections. + workqueue->queue(new Write_sections_task(layout, of, output_sections_blocker, + final_blocker)); + + // Queue a task to write out everything else. + workqueue->queue(new Write_data_task(layout, symtab, of, final_blocker)); + + // Queue a task for each input object to relocate the sections and + // write out the local symbols. + for (Input_objects::Relobj_iterator p = input_objects->relobj_begin(); + p != input_objects->relobj_end(); + ++p) + workqueue->queue(new Relocate_task(symtab, layout, *p, of, + input_sections_blocker, + output_sections_blocker, + final_blocker)); + + // Queue a task to write out the output sections which depend on + // input sections. If there are any sections which require + // postprocessing, then we need to do this last, since it may resize + // the output file. + if (!any_postprocessing_sections) + { + Task* t = new Write_after_input_sections_task(layout, of, + input_sections_blocker, + final_blocker); + workqueue->queue(t); + } + else + { + Task_token* new_final_blocker = new Task_token(true); + new_final_blocker->add_blocker(); + Task* t = new Write_after_input_sections_task(layout, of, + final_blocker, + new_final_blocker); + workqueue->queue(t); + final_blocker = new_final_blocker; + } + + // Create tasks for tree-style build ID computation, if necessary. + final_blocker = layout->queue_build_id_tasks(workqueue, final_blocker, of); + + // Queue a task to close the output file. This will be blocked by + // FINAL_BLOCKER. + workqueue->queue(new Task_function(new Close_task_runner(&options, layout, + of), + final_blocker, + "Task_function Close_task_runner")); +} + +} // End namespace gold. diff --git a/binutils-2.25/gold/gold.h b/binutils-2.25/gold/gold.h new file mode 100644 index 00000000..ef95f530 --- /dev/null +++ b/binutils-2.25/gold/gold.h @@ -0,0 +1,313 @@ +// gold.h -- general definitions for gold -*- C++ -*- + +// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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. + +#ifndef GOLD_GOLD_H +#define GOLD_GOLD_H + +#include "config.h" +#include "ansidecl.h" + +#include +#include +#include +#include +#include + +#include "system.h" + +namespace gold +{ + +// General declarations. + +class General_options; +class Command_line; +class Dirsearch; +class Input_objects; +class Mapfile; +class Symbol; +class Symbol_table; +class Layout; +class Task; +class Workqueue; +class Output_file; +template +struct Relocate_info; + +// Exit status codes. + +enum Exit_status +{ + GOLD_OK = EXIT_SUCCESS, + GOLD_ERR = EXIT_FAILURE, + GOLD_FALLBACK = EXIT_FAILURE + 1 +}; + +// Some basic types. For these we use lower case initial letters. + +// For an offset in an input or output file, use off_t. Note that +// this will often be a 64-bit type even for a 32-bit build. + +// The size of a section if we are going to look at the contents. +typedef size_t section_size_type; + +// An offset within a section when we are looking at the contents. +typedef ptrdiff_t section_offset_type; + +// The name of the program as used in error messages. +extern const char* program_name; + +// This function is called to exit the program. Status is true to +// exit success (0) and false to exit failure (1). +extern void +gold_exit(Exit_status status) ATTRIBUTE_NORETURN; + +// This function is called to emit an error message and then +// immediately exit with failure. +extern void +gold_fatal(const char* format, ...) ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF_1; + +// This function is called to issue an error. This will cause gold to +// eventually exit with failure. +extern void +gold_error(const char* msg, ...) ATTRIBUTE_PRINTF_1; + +// This function is called to issue a warning. +extern void +gold_warning(const char* msg, ...) ATTRIBUTE_PRINTF_1; + +// This function is called to print an informational message. +extern void +gold_info(const char* msg, ...) ATTRIBUTE_PRINTF_1; + +// This function is called to emit an error message and then +// immediately exit with fallback status (e.g., when +// --incremental-update fails and the link needs to be restarted +// with --incremental-full). +extern void +gold_fallback(const char* format, ...) ATTRIBUTE_NORETURN ATTRIBUTE_PRINTF_1; + +// Work around a bug in gcc 4.3.0. http://gcc.gnu.org/PR35546 . This +// can probably be removed after the bug has been fixed for a while. +#ifdef HAVE_TEMPLATE_ATTRIBUTES +#define TEMPLATE_ATTRIBUTE_PRINTF_4 ATTRIBUTE_PRINTF_4 +#else +#define TEMPLATE_ATTRIBUTE_PRINTF_4 +#endif + +// This function is called to issue an error at the location of a +// reloc. +template +extern void +gold_error_at_location(const Relocate_info*, + size_t, off_t, const char* format, ...) + TEMPLATE_ATTRIBUTE_PRINTF_4; + +// This function is called to issue a warning at the location of a +// reloc. +template +extern void +gold_warning_at_location(const Relocate_info*, + size_t, off_t, const char* format, ...) + TEMPLATE_ATTRIBUTE_PRINTF_4; + +// This function is called to report an undefined symbol without +// a relocation (e.g., referenced by a dynamic object). SYM is +// the undefined symbol. The file name associated with the SYM +// is used to print a location for the undefined symbol. +extern void +gold_undefined_symbol(const Symbol*); + +// This function is called to report an undefined symbol resulting +// from a relocation. SYM is the undefined symbol. RELINFO is the +// general relocation info. RELNUM is the number of the reloc, +// and RELOFFSET is the reloc's offset. +template +extern void +gold_undefined_symbol_at_location(const Symbol*, + const Relocate_info*, + size_t, off_t); + +// This is function is called in some cases if we run out of memory. +extern void +gold_nomem() ATTRIBUTE_NORETURN; + +// In versions of gcc before 4.3, using __FUNCTION__ in a template +// function can cause gcc to get confused about whether or not the +// function can return. See http://gcc.gnu.org/PR30988. Use a macro +// to avoid the problem. This can be removed when we no longer need +// to care about gcc versions before 4.3. +#if defined(__GNUC__) && GCC_VERSION < 4003 +#define FUNCTION_NAME static_cast(__FUNCTION__) +#else +#define FUNCTION_NAME __FUNCTION__ +#endif + +// This macro and function are used in cases which can not arise if +// the code is written correctly. + +#define gold_unreachable() \ + (gold::do_gold_unreachable(__FILE__, __LINE__, FUNCTION_NAME)) + +extern void do_gold_unreachable(const char*, int, const char*) + ATTRIBUTE_NORETURN; + +// Assertion check. + +#define gold_assert(expr) ((void)(!(expr) ? gold_unreachable(), 0 : 0)) + +// Print version information. +extern void +print_version(bool print_short); + +// Get the version string. +extern const char* +get_version_string(); + +// Convert numeric types without unnoticed loss of precision. +template +inline To +convert_types(const From from) +{ + To to = from; + gold_assert(static_cast(to) == from); + return to; +} + +// A common case of convert_types<>: convert to section_size_type. +template +inline section_size_type +convert_to_section_size_type(const From from) +{ return convert_types(from); } + +// Queue up the first set of tasks. +extern void +queue_initial_tasks(const General_options&, + Dirsearch&, + const Command_line&, + Workqueue*, + Input_objects*, + Symbol_table*, + Layout*, + Mapfile*); + +// Queue up the set of tasks to be done before +// the middle set of tasks. Only used when garbage +// collection is to be done. +extern void +queue_middle_gc_tasks(const General_options&, + const Task*, + const Input_objects*, + Symbol_table*, + Layout*, + Workqueue*, + Mapfile*); + +// Queue up the middle set of tasks. +extern void +queue_middle_tasks(const General_options&, + const Task*, + const Input_objects*, + Symbol_table*, + Layout*, + Workqueue*, + Mapfile*); + +// Queue up the final set of tasks. +extern void +queue_final_tasks(const General_options&, + const Input_objects*, + const Symbol_table*, + Layout*, + Workqueue*, + Output_file* of); + +inline bool +is_prefix_of(const char* prefix, const char* str) +{ + return strncmp(prefix, str, strlen(prefix)) == 0; +} + +const char* const cident_section_start_prefix = "__start_"; +const char* const cident_section_stop_prefix = "__stop_"; + +// Returns true if the name is a valid C identifier +inline bool +is_cident(const char* name) +{ + return (name[strspn(name, + ("0123456789" + "ABCDEFGHIJKLMNOPWRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "_"))] + == '\0'); +} + +// We sometimes need to hash strings. Ideally we should use std::tr1::hash or +// __gnu_cxx::hash on some systems but there is no guarantee that either +// one is available. For portability, we define simple string hash functions. + +template +inline size_t +string_hash(const Char_type* s, size_t length) +{ + // This is the hash function used by the dynamic linker for + // DT_GNU_HASH entries. I compared this to a Fowler/Noll/Vo hash + // for a C++ program with 385,775 global symbols. This hash + // function was very slightly worse. However, it is much faster to + // compute. Overall wall clock time was a win. + const unsigned char* p = reinterpret_cast(s); + size_t h = 5381; + for (size_t i = 0; i < length * sizeof(Char_type); ++i) + h = h * 33 + *p++; + return h; +} + +// Same as above except we expect the string to be zero terminated. + +template +inline size_t +string_hash(const Char_type* s) +{ + const unsigned char* p = reinterpret_cast(s); + size_t h = 5381; + for (size_t i = 0; s[i] != 0; ++i) + { + for (size_t j = 0; j < sizeof(Char_type); j++) + h = h * 33 + *p++; + } + + return h; +} + +// Return whether STRING contains a wildcard character. This is used +// to speed up matching. + +inline bool +is_wildcard_string(const char* s) +{ + return strpbrk(s, "?*[") != NULL; +} + +} // End namespace gold. + +#endif // !defined(GOLD_GOLD_H) diff --git a/binutils-2.25/gold/i386.cc b/binutils-2.25/gold/i386.cc new file mode 100644 index 00000000..6a3280df --- /dev/null +++ b/binutils-2.25/gold/i386.cc @@ -0,0 +1,4168 @@ +// i386.cc -- i386 target support for gold. + +// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 +// Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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 + +#include "elfcpp.h" +#include "dwarf.h" +#include "parameters.h" +#include "reloc.h" +#include "i386.h" +#include "object.h" +#include "symtab.h" +#include "layout.h" +#include "output.h" +#include "copy-relocs.h" +#include "target.h" +#include "target-reloc.h" +#include "target-select.h" +#include "tls.h" +#include "freebsd.h" +#include "nacl.h" +#include "gc.h" + +namespace +{ + +using namespace gold; + +// A class to handle the PLT data. +// This is an abstract base class that handles most of the linker details +// but does not know the actual contents of PLT entries. The derived +// classes below fill in those details. + +class Output_data_plt_i386 : public Output_section_data +{ + public: + typedef Output_data_reloc Reloc_section; + + Output_data_plt_i386(Layout*, uint64_t addralign, + Output_data_space*, Output_data_space*); + + // Add an entry to the PLT. + void + add_entry(Symbol_table*, Layout*, Symbol* gsym); + + // Add an entry to the PLT for a local STT_GNU_IFUNC symbol. + unsigned int + add_local_ifunc_entry(Symbol_table*, Layout*, + Sized_relobj_file<32, false>* relobj, + unsigned int local_sym_index); + + // Return the .rel.plt section data. + Reloc_section* + rel_plt() const + { return this->rel_; } + + // Return where the TLS_DESC relocations should go. + Reloc_section* + rel_tls_desc(Layout*); + + // Return where the IRELATIVE relocations should go. + Reloc_section* + rel_irelative(Symbol_table*, Layout*); + + // Return whether we created a section for IRELATIVE relocations. + bool + has_irelative_section() const + { return this->irelative_rel_ != NULL; } + + // Return the number of PLT entries. + unsigned int + entry_count() const + { return this->count_ + this->irelative_count_; } + + // Return the offset of the first non-reserved PLT entry. + unsigned int + first_plt_entry_offset() + { return this->get_plt_entry_size(); } + + // Return the size of a PLT entry. + 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 + address_for_global(const Symbol*); + + // Return the PLT address to use for a local symbol. + uint64_t + address_for_local(const Relobj*, unsigned int symndx); + + // Add .eh_frame information for the PLT. + void + add_eh_frame(Layout* layout) + { this->do_add_eh_frame(layout); } + + protected: + // Fill the first PLT entry, given the pointer to the PLT section data + // and the runtime address of the GOT. + void + 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); + } + + virtual unsigned int + do_get_plt_entry_size() const = 0; + + virtual void + do_fill_first_plt_entry(unsigned char* pov, + elfcpp::Elf_types<32>::Elf_Addr got_address) = 0; + + 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; + + virtual void + do_add_eh_frame(Layout*) = 0; + + 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 unsigned char plt_eh_frame_cie[plt_eh_frame_cie_size]; + + private: + // Set the final size. + void + set_final_data_size() + { + this->set_data_size((this->count_ + this->irelative_count_ + 1) + * this->get_plt_entry_size()); + } + + // Write out the PLT data. + void + do_write(Output_file*); + + // We keep a list of global STT_GNU_IFUNC symbols, each with its + // offset in the GOT. + struct Global_ifunc + { + Symbol* sym; + unsigned int got_offset; + }; + + // We keep a list of local STT_GNU_IFUNC symbols, each with its + // offset in the GOT. + struct Local_ifunc + { + Sized_relobj_file<32, false>* object; + unsigned int local_sym_index; + unsigned int got_offset; + }; + + // A pointer to the Layout class, so that we can find the .dynamic + // section when we write out the GOT PLT section. + Layout* layout_; + // The reloc section. + Reloc_section* rel_; + // The TLS_DESC relocations, if necessary. These must follow the + // regular PLT relocs. + Reloc_section* tls_desc_rel_; + // The IRELATIVE relocations, if necessary. These must follow the + // regular relocatoins and the TLS_DESC relocations. + Reloc_section* irelative_rel_; + // The .got.plt section. + Output_data_space* got_plt_; + // The part of the .got.plt section used for IRELATIVE relocs. + Output_data_space* got_irelative_; + // The number of PLT entries. + unsigned int count_; + // Number of PLT entries with R_386_IRELATIVE relocs. These follow + // the regular PLT entries. + unsigned int irelative_count_; + // Global STT_GNU_IFUNC symbols. + std::vector global_ifuncs_; + // Local STT_GNU_IFUNC symbols. + std::vector 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 +// http://www.lsd.ic.unicamp.br/~oliva/writeups/TLS/RFC-TLSDESC-x86.txt + +class Target_i386 : public Sized_target<32, false> +{ + public: + typedef Output_data_reloc Reloc_section; + + 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), + got_mod_index_offset_(-1U), tls_base_symbol_defined_(false) + { } + + // 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); + + // Scan the relocations to look for symbol adjustments. + void + 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); + + // Finalize the sections. + void + do_finalize_sections(Layout*, const Input_objects*, Symbol_table*); + + // Return the value to use for a dynamic which requires special + // treatment. + uint64_t + do_dynsym_value(const Symbol*) const; + + // Relocate a section. + void + relocate_section(const Relocate_info<32, false>*, + unsigned int sh_type, + const unsigned char* prelocs, + size_t reloc_count, + Output_section* output_section, + bool needs_special_offset_handling, + unsigned char* view, + elfcpp::Elf_types<32>::Elf_Addr view_address, + section_size_type view_size, + const Reloc_symbol_changes*); + + // Scan the relocs during a relocatable link. + void + scan_relocatable_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, + Relocatable_relocs*); + + // Emit relocations for a section. + void + relocate_relocs(const Relocate_info<32, false>*, + unsigned int sh_type, + const unsigned char* prelocs, + size_t reloc_count, + Output_section* output_section, + elfcpp::Elf_types<32>::Elf_Off offset_in_output_section, + const Relocatable_relocs*, + unsigned char* view, + elfcpp::Elf_types<32>::Elf_Addr view_address, + section_size_type view_size, + unsigned char* reloc_view, + section_size_type reloc_view_size); + + // Return a string used to fill a code section with nops. + std::string + do_code_fill(section_size_type length) const; + + // Return whether SYM is defined by the ABI. + bool + do_is_defined_by_abi(const Symbol* sym) const + { return strcmp(sym->name(), "___tls_get_addr") == 0; } + + // Return whether a symbol name implies a local label. The UnixWare + // 2.1 cc generates temporary symbols that start with .X, so we + // recognize them here. FIXME: do other SVR4 compilers also use .X?. + // If so, we should move the .X recognition into + // Target::do_is_local_label_name. + bool + do_is_local_label_name(const char* name) const + { + if (name[0] == '.' && name[1] == 'X') + return true; + return Target::do_is_local_label_name(name); + } + + // Return the PLT address to use for a global symbol. + uint64_t + do_plt_address_for_global(const Symbol* gsym) const + { return this->plt_section()->address_for_global(gsym); } + + uint64_t + do_plt_address_for_local(const Relobj* relobj, unsigned int symndx) const + { return this->plt_section()->address_for_local(relobj, symndx); } + + // We can tell whether we take the address of a function. + inline bool + do_can_check_for_function_pointers() const + { return true; } + + // Return the base for a DW_EH_PE_datarel encoding. + uint64_t + do_ehframe_datarel_base() const; + + // Return whether SYM is call to a non-split function. + bool + do_is_call_to_non_split(const Symbol* sym, unsigned int) const; + + // Adjust -fsplit-stack code which calls non-split-stack code. + void + 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; + + // Return the size of the GOT section. + section_size_type + got_size() const + { + gold_assert(this->got_ != NULL); + return this->got_->data_size(); + } + + // Return the number of entries in the GOT. + unsigned int + got_entry_count() const + { + if (this->got_ == NULL) + return 0; + return this->got_size() / 4; + } + + // Return the number of entries in the PLT. + unsigned int + plt_entry_count() const; + + // Return the offset of the first non-reserved PLT entry. + unsigned int + first_plt_entry_offset() const; + + // Return the size of each PLT entry. + 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 + { + static inline int + + get_reference_flags(unsigned int r_type); + + inline void + 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, + bool is_discarded); + + inline void + 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); + + 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, + unsigned int r_type, + 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, + const elfcpp::Rel<32, false>& reloc, + unsigned int r_type, + Symbol* gsym); + + inline bool + possible_function_pointer_reloc(unsigned int r_type); + + bool + reloc_needs_plt_for_ifunc(Sized_relobj_file<32, false>*, + unsigned int r_type); + + static void + unsupported_reloc_local(Sized_relobj_file<32, false>*, unsigned int r_type); + + static void + unsupported_reloc_global(Sized_relobj_file<32, false>*, unsigned int r_type, + Symbol*); + }; + + // The class which implements relocation. + class Relocate + { + public: + Relocate() + : skip_call_tls_get_addr_(false), + local_dynamic_type_(LOCAL_DYNAMIC_NONE) + { } + + ~Relocate() + { + if (this->skip_call_tls_get_addr_) + { + // FIXME: This needs to specify the location somehow. + gold_error(_("missing expected TLS relocation")); + } + } + + // 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, + Output_section* output_section); + + // Do a relocation. Return false if the caller should not issue + // any warnings about this relocation. + inline bool + relocate(const Relocate_info<32, false>*, Target_i386*, Output_section*, + 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, + section_size_type); + + private: + // Do a TLS relocation. + inline void + relocate_tls(const Relocate_info<32, false>*, Target_i386* target, + 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, + section_size_type); + + // Do a TLS General-Dynamic to Initial-Exec transition. + inline void + tls_gd_to_ie(const Relocate_info<32, false>*, size_t relnum, + Output_segment* tls_segment, + const elfcpp::Rel<32, false>&, unsigned int r_type, + elfcpp::Elf_types<32>::Elf_Addr value, + unsigned char* view, + section_size_type view_size); + + // Do a TLS General-Dynamic to Local-Exec transition. + inline void + tls_gd_to_le(const Relocate_info<32, false>*, size_t relnum, + Output_segment* tls_segment, + const elfcpp::Rel<32, false>&, unsigned int r_type, + elfcpp::Elf_types<32>::Elf_Addr value, + unsigned char* view, + section_size_type view_size); + + // Do a TLS_GOTDESC or TLS_DESC_CALL General-Dynamic to Initial-Exec + // transition. + inline void + tls_desc_gd_to_ie(const Relocate_info<32, false>*, size_t relnum, + Output_segment* tls_segment, + const elfcpp::Rel<32, false>&, unsigned int r_type, + elfcpp::Elf_types<32>::Elf_Addr value, + unsigned char* view, + section_size_type view_size); + + // Do a TLS_GOTDESC or TLS_DESC_CALL General-Dynamic to Local-Exec + // transition. + inline void + tls_desc_gd_to_le(const Relocate_info<32, false>*, size_t relnum, + Output_segment* tls_segment, + const elfcpp::Rel<32, false>&, unsigned int r_type, + elfcpp::Elf_types<32>::Elf_Addr value, + unsigned char* view, + section_size_type view_size); + + // Do a TLS Local-Dynamic to Local-Exec transition. + inline void + tls_ld_to_le(const Relocate_info<32, false>*, size_t relnum, + Output_segment* tls_segment, + const elfcpp::Rel<32, false>&, unsigned int r_type, + elfcpp::Elf_types<32>::Elf_Addr value, + unsigned char* view, + section_size_type view_size); + + // Do a TLS Initial-Exec to Local-Exec transition. + static inline void + tls_ie_to_le(const Relocate_info<32, false>*, size_t relnum, + Output_segment* tls_segment, + const elfcpp::Rel<32, false>&, unsigned int r_type, + elfcpp::Elf_types<32>::Elf_Addr value, + unsigned char* view, + section_size_type view_size); + + // We need to keep track of which type of local dynamic relocation + // we have seen, so that we can optimize R_386_TLS_LDO_32 correctly. + enum Local_dynamic_type + { + LOCAL_DYNAMIC_NONE, + LOCAL_DYNAMIC_SUN, + LOCAL_DYNAMIC_GNU + }; + + // This is set if we should skip the next reloc, which should be a + // PLT32 reloc against ___tls_get_addr. + bool skip_call_tls_get_addr_; + // The type of local dynamic relocation we have seen in the section + // being relocated, if any. + Local_dynamic_type local_dynamic_type_; + }; + + // A class which returns the size required for a relocation type, + // used while scanning relocs during a relocatable link. + class Relocatable_size_for_reloc + { + public: + unsigned int + get_size_for_reloc(unsigned int, Relobj*); + }; + + // Adjust TLS relocation type based on the options and whether this + // is a local symbol. + static tls::Tls_optimization + optimize_tls_reloc(bool is_final, int r_type); + + // Get the GOT section, creating it if necessary. + Output_data_got<32, false>* + got_section(Symbol_table*, Layout*); + + // Get the GOT PLT section. + Output_data_space* + got_plt_section() const + { + gold_assert(this->got_plt_ != NULL); + return this->got_plt_; + } + + // Get the GOT section for TLSDESC entries. + Output_data_got<32, false>* + got_tlsdesc_section() const + { + gold_assert(this->got_tlsdesc_ != NULL); + return this->got_tlsdesc_; + } + + // Create the PLT section. + void + make_plt_section(Symbol_table* symtab, Layout* layout); + + // Create a PLT entry for a global symbol. + void + make_plt_entry(Symbol_table*, Layout*, Symbol*); + + // Create a PLT entry for a local STT_GNU_IFUNC symbol. + void + make_local_ifunc_plt_entry(Symbol_table*, Layout*, + Sized_relobj_file<32, false>* relobj, + unsigned int local_sym_index); + + // Define the _TLS_MODULE_BASE_ symbol in the TLS segment. + void + define_tls_base_symbol(Symbol_table*, Layout*); + + // Create a GOT entry for the TLS module index. + unsigned int + got_mod_index_entry(Symbol_table* symtab, Layout* layout, + Sized_relobj_file<32, false>* object); + + // Get the PLT section. + Output_data_plt_i386* + plt_section() const + { + gold_assert(this->plt_ != NULL); + return this->plt_; + } + + // Get the dynamic reloc section, creating it if necessary. + Reloc_section* + rel_dyn_section(Layout*); + + // Get the section to use for TLS_DESC relocations. + Reloc_section* + rel_tls_desc_section(Layout*) const; + + // Get the section to use for IRELATIVE relocations. + Reloc_section* + rel_irelative_section(Layout*); + + // Add a potential copy relocation. + void + copy_reloc(Symbol_table* symtab, Layout* layout, + Sized_relobj_file<32, false>* object, + unsigned int shndx, Output_section* output_section, + Symbol* sym, const elfcpp::Rel<32, false>& reloc) + { + this->copy_relocs_.copy_reloc(symtab, layout, + symtab->get_sized_symbol<32>(sym), + object, shndx, output_section, reloc, + this->rel_dyn_section(layout)); + } + + // Information about this specific target which we pass to the + // general Target structure. + static const Target::Target_info i386_info; + + // The types of GOT entries needed for this platform. + // These values are exposed to the ABI in an incremental link. + // Do not renumber existing values without changing the version + // number of the .gnu_incremental_inputs section. + enum Got_type + { + GOT_TYPE_STANDARD = 0, // GOT entry for a regular symbol + GOT_TYPE_TLS_NOFFSET = 1, // GOT entry for negative TLS offset + GOT_TYPE_TLS_OFFSET = 2, // GOT entry for positive TLS offset + GOT_TYPE_TLS_PAIR = 3, // GOT entry for TLS module/offset pair + GOT_TYPE_TLS_DESC = 4 // GOT entry for TLS_DESC pair + }; + + // The GOT section. + Output_data_got<32, false>* got_; + // The PLT section. + Output_data_plt_i386* plt_; + // The GOT PLT section. + Output_data_space* got_plt_; + // The GOT section for IRELATIVE relocations. + Output_data_space* got_irelative_; + // The GOT section for TLSDESC relocations. + Output_data_got<32, false>* got_tlsdesc_; + // The _GLOBAL_OFFSET_TABLE_ symbol. + Symbol* global_offset_table_; + // The dynamic reloc section. + Reloc_section* rel_dyn_; + // The section to use for IRELATIVE relocs. + Reloc_section* rel_irelative_; + // Relocs saved to avoid a COPY reloc. + Copy_relocs copy_relocs_; + // Offset of the GOT entry for the TLS module index. + unsigned int got_mod_index_offset_; + // True if the _TLS_MODULE_BASE_ symbol has been defined. + bool tls_base_symbol_defined_; +}; + +const Target::Target_info Target_i386::i386_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 + "/usr/lib/libc.so.1", // dynamic_linker + 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 + 0, // large_common_section_flags + NULL, // attributes_section + NULL, // attributes_vendor + "_start" // entry_symbol_name +}; + +// Get the GOT section, creating it if necessary. + +Output_data_got<32, false>* +Target_i386::got_section(Symbol_table* symtab, Layout* layout) +{ + if (this->got_ == NULL) + { + gold_assert(symtab != NULL && layout != NULL); + + this->got_ = new Output_data_got<32, false>(); + + // When using -z now, we can treat .got.plt as a relro section. + // Without -z now, it is modified after program startup by lazy + // PLT relocations. + bool is_got_plt_relro = parameters->options().now(); + Output_section_order got_order = (is_got_plt_relro + ? ORDER_RELRO + : ORDER_RELRO_LAST); + Output_section_order got_plt_order = (is_got_plt_relro + ? ORDER_RELRO + : ORDER_NON_RELRO_FIRST); + + layout->add_output_section_data(".got", elfcpp::SHT_PROGBITS, + (elfcpp::SHF_ALLOC + | elfcpp::SHF_WRITE), + this->got_, got_order, true); + + this->got_plt_ = new Output_data_space(4, "** GOT PLT"); + layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS, + (elfcpp::SHF_ALLOC + | elfcpp::SHF_WRITE), + this->got_plt_, got_plt_order, + is_got_plt_relro); + + // The first three entries are reserved. + this->got_plt_->set_current_data_size(3 * 4); + + if (!is_got_plt_relro) + { + // Those bytes can go into the relro segment. + layout->increase_relro(3 * 4); + } + + // Define _GLOBAL_OFFSET_TABLE_ at the start of the PLT. + this->global_offset_table_ = + symtab->define_in_output_data("_GLOBAL_OFFSET_TABLE_", NULL, + Symbol_table::PREDEFINED, + this->got_plt_, + 0, 0, elfcpp::STT_OBJECT, + elfcpp::STB_LOCAL, + elfcpp::STV_HIDDEN, 0, + false, false); + + // If there are any IRELATIVE relocations, they get GOT entries + // in .got.plt after the jump slot relocations. + this->got_irelative_ = new Output_data_space(4, "** GOT IRELATIVE PLT"); + layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS, + (elfcpp::SHF_ALLOC + | elfcpp::SHF_WRITE), + this->got_irelative_, + got_plt_order, is_got_plt_relro); + + // If there are any TLSDESC relocations, they get GOT entries in + // .got.plt after the jump slot entries. + this->got_tlsdesc_ = new Output_data_got<32, false>(); + layout->add_output_section_data(".got.plt", elfcpp::SHT_PROGBITS, + (elfcpp::SHF_ALLOC + | elfcpp::SHF_WRITE), + this->got_tlsdesc_, + got_plt_order, is_got_plt_relro); + } + + return this->got_; +} + +// Get the dynamic reloc section, creating it if necessary. + +Target_i386::Reloc_section* +Target_i386::rel_dyn_section(Layout* layout) +{ + if (this->rel_dyn_ == NULL) + { + gold_assert(layout != NULL); + this->rel_dyn_ = new Reloc_section(parameters->options().combreloc()); + layout->add_output_section_data(".rel.dyn", elfcpp::SHT_REL, + elfcpp::SHF_ALLOC, this->rel_dyn_, + ORDER_DYNAMIC_RELOCS, false); + } + return this->rel_dyn_; +} + +// Get the section to use for IRELATIVE relocs, creating it if +// necessary. These go in .rel.dyn, but only after all other dynamic +// relocations. They need to follow the other dynamic relocations so +// that they can refer to global variables initialized by those +// relocs. + +Target_i386::Reloc_section* +Target_i386::rel_irelative_section(Layout* layout) +{ + if (this->rel_irelative_ == NULL) + { + // Make sure we have already create the dynamic reloc section. + this->rel_dyn_section(layout); + this->rel_irelative_ = new Reloc_section(false); + layout->add_output_section_data(".rel.dyn", elfcpp::SHT_REL, + elfcpp::SHF_ALLOC, this->rel_irelative_, + ORDER_DYNAMIC_RELOCS, false); + gold_assert(this->rel_dyn_->output_section() + == this->rel_irelative_->output_section()); + } + return this->rel_irelative_; +} + +// Create the PLT section. The ordinary .got section is an argument, +// since we need to refer to the start. We also create our own .got +// 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(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_() +{ + this->rel_ = new Reloc_section(false); + layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL, + elfcpp::SHF_ALLOC, this->rel_, + ORDER_DYNAMIC_PLT_RELOCS, false); +} + +void +Output_data_plt_i386::do_adjust_output_section(Output_section* os) +{ + // UnixWare sets the entsize of .plt to 4, and so does the old GNU + // linker, and so do we. + os->set_entsize(4); +} + +// Add an entry to the PLT. + +void +Output_data_plt_i386::add_entry(Symbol_table* symtab, Layout* layout, + Symbol* gsym) +{ + gold_assert(!gsym->has_plt_offset()); + + // Every PLT entry needs a reloc. + if (gsym->type() == elfcpp::STT_GNU_IFUNC + && gsym->can_use_relative_reloc(false)) + { + 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(); + this->got_irelative_->set_current_data_size(got_offset + 4); + Reloc_section* rel = this->rel_irelative(symtab, layout); + rel->add_symbolless_global_addend(gsym, elfcpp::R_386_IRELATIVE, + this->got_irelative_, got_offset); + struct Global_ifunc gi; + gi.sym = gsym; + gi.got_offset = got_offset; + this->global_ifuncs_.push_back(gi); + } + else + { + // When setting the PLT offset we skip the initial reserved PLT + // entry. + gsym->set_plt_offset((this->count_ + 1) * this->get_plt_entry_size()); + + ++this->count_; + + section_offset_type got_offset = this->got_plt_->current_data_size(); + + // Every PLT entry needs a GOT entry which points back to the + // PLT entry (this will be changed by the dynamic linker, + // normally lazily when the function is called). + this->got_plt_->set_current_data_size(got_offset + 4); + + gsym->set_needs_dynsym_entry(); + this->rel_->add_global(gsym, elfcpp::R_386_JUMP_SLOT, this->got_plt_, + got_offset); + } + + // Note that we don't need to save the symbol. The contents of the + // PLT are independent of which symbols are used. The symbols only + // appear in the relocations. +} + +// Add an entry to the PLT for a local STT_GNU_IFUNC symbol. Return +// the PLT offset. + +unsigned int +Output_data_plt_i386::add_local_ifunc_entry( + Symbol_table* symtab, + Layout* layout, + Sized_relobj_file<32, false>* relobj, + unsigned int local_sym_index) +{ + 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(); + + // Every PLT entry needs a GOT entry which points back to the PLT + // entry. + this->got_irelative_->set_current_data_size(got_offset + 4); + + // Every PLT entry needs a reloc. + Reloc_section* rel = this->rel_irelative(symtab, layout); + rel->add_symbolless_local_addend(relobj, local_sym_index, + elfcpp::R_386_IRELATIVE, + this->got_irelative_, got_offset); + + struct Local_ifunc li; + li.object = relobj; + li.local_sym_index = local_sym_index; + li.got_offset = got_offset; + this->local_ifuncs_.push_back(li); + + return plt_offset; +} + +// Return where the TLS_DESC relocations should go, creating it if +// necessary. These follow the JUMP_SLOT relocations. + +Output_data_plt_i386::Reloc_section* +Output_data_plt_i386::rel_tls_desc(Layout* layout) +{ + if (this->tls_desc_rel_ == NULL) + { + this->tls_desc_rel_ = new Reloc_section(false); + layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL, + elfcpp::SHF_ALLOC, this->tls_desc_rel_, + ORDER_DYNAMIC_PLT_RELOCS, false); + gold_assert(this->tls_desc_rel_->output_section() + == this->rel_->output_section()); + } + return this->tls_desc_rel_; +} + +// Return where the IRELATIVE relocations should go in the PLT. These +// follow the JUMP_SLOT and TLS_DESC relocations. + +Output_data_plt_i386::Reloc_section* +Output_data_plt_i386::rel_irelative(Symbol_table* symtab, Layout* layout) +{ + if (this->irelative_rel_ == NULL) + { + // Make sure we have a place for the TLS_DESC relocations, in + // case we see any later on. + this->rel_tls_desc(layout); + this->irelative_rel_ = new Reloc_section(false); + layout->add_output_section_data(".rel.plt", elfcpp::SHT_REL, + elfcpp::SHF_ALLOC, this->irelative_rel_, + ORDER_DYNAMIC_PLT_RELOCS, false); + gold_assert(this->irelative_rel_->output_section() + == this->rel_->output_section()); + + if (parameters->doing_static_link()) + { + // A statically linked executable will only have a .rel.plt + // section to hold R_386_IRELATIVE relocs for STT_GNU_IFUNC + // symbols. The library will use these symbols to locate + // the IRELATIVE relocs at program startup time. + symtab->define_in_output_data("__rel_iplt_start", NULL, + Symbol_table::PREDEFINED, + this->irelative_rel_, 0, 0, + elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL, + elfcpp::STV_HIDDEN, 0, false, true); + symtab->define_in_output_data("__rel_iplt_end", NULL, + Symbol_table::PREDEFINED, + this->irelative_rel_, 0, 0, + elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL, + elfcpp::STV_HIDDEN, 0, true, true); + } + } + return this->irelative_rel_; +} + +// Return the PLT address to use for a global symbol. + +uint64_t +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) * this->get_plt_entry_size(); + return this->address() + offset + gsym->plt_offset(); +} + +// Return the PLT address to use for a local symbol. These are always +// IRELATIVE relocs. + +uint64_t +Output_data_plt_i386::address_for_local(const Relobj* object, + unsigned int r_sym) +{ + return (this->address() + + (this->count_ + 1) * this->get_plt_entry_size() + + object->local_plt_offset(r_sym)); +} + +// The first entry in the PLT for an executable. + +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 + 0xff, 0x25, // jmp indirect + 0, 0, 0, 0, // replaced with address of .got + 8 + 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] = +{ + 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] = +{ + 0xff, 0x25, // jmp indirect + 0, 0, 0, 0, // replaced with address of symbol in .got + 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 +}; + +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] = +{ + 0xff, 0xa3, // jmp *offset(%ebx) + 0, 0, 0, 0, // replaced with offset of symbol in .got + 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 +}; + +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 +Output_data_plt_i386::plt_eh_frame_cie[plt_eh_frame_cie_size] = +{ + 1, // CIE version. + 'z', // Augmentation: augmentation size included. + 'R', // Augmentation: FDE encoding included. + '\0', // End of augmentation string. + 1, // Code alignment factor. + 0x7c, // Data alignment factor. + 8, // Return address column. + 1, // Augmentation size. + (elfcpp::DW_EH_PE_pcrel // FDE encoding. + | elfcpp::DW_EH_PE_sdata4), + elfcpp::DW_CFA_def_cfa, 4, 4, // DW_CFA_def_cfa: r4 (esp) ofs 4. + elfcpp::DW_CFA_offset + 8, 1, // DW_CFA_offset: r8 (eip) at cfa-4. + elfcpp::DW_CFA_nop, // Align to 16 bytes. + elfcpp::DW_CFA_nop +}; + +const unsigned char +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. + 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 + 10, // Advance 10 to __PLT__ + 16. + elfcpp::DW_CFA_def_cfa_expression, // DW_CFA_def_cfa_expression. + 11, // Block length. + elfcpp::DW_OP_breg4, 4, // Push %esp + 4. + elfcpp::DW_OP_breg8, 0, // Push %eip. + elfcpp::DW_OP_lit15, // Push 0xf. + elfcpp::DW_OP_and, // & (%eip & 0xf). + elfcpp::DW_OP_lit11, // Push 0xb. + elfcpp::DW_OP_ge, // >= ((%eip & 0xf) >= 0xb) + elfcpp::DW_OP_lit2, // Push 2. + elfcpp::DW_OP_shl, // << (((%eip & 0xf) >= 0xb) << 2) + elfcpp::DW_OP_plus, // + ((((%eip&0xf)>=0xb)<<2)+%esp+4 + elfcpp::DW_CFA_nop, // Align to 32 bytes. + elfcpp::DW_CFA_nop, + elfcpp::DW_CFA_nop, + elfcpp::DW_CFA_nop +}; + +// Write out the PLT. This uses the hand-coded instructions above, +// and adjusts them as needed. This is all specified by the i386 ELF +// Processor Supplement. + +void +Output_data_plt_i386::do_write(Output_file* of) +{ + const off_t offset = this->offset(); + const section_size_type oview_size = + convert_to_section_size_type(this->data_size()); + unsigned char* const oview = of->get_output_view(offset, oview_size); + + const off_t got_file_offset = this->got_plt_->offset(); + gold_assert(parameters->incremental_update() + || (got_file_offset + this->got_plt_->data_size() + == this->got_irelative_->offset())); + const section_size_type got_size = + convert_to_section_size_type(this->got_plt_->data_size() + + this->got_irelative_->data_size()); + unsigned char* const got_view = of->get_output_view(got_file_offset, + got_size); + + unsigned char* pov = oview; + + elfcpp::Elf_types<32>::Elf_Addr plt_address = this->address(); + elfcpp::Elf_types<32>::Elf_Addr got_address = this->got_plt_->address(); + + this->fill_first_plt_entry(pov, got_address); + pov += this->get_plt_entry_size(); + + unsigned char* got_pov = got_view; + + // The first entry in the GOT is the address of the .dynamic section + // aka the PT_DYNAMIC segment. The next two entries are reserved. + // We saved space for them when we created the section in + // Target_i386::got_section. + Output_section* dynamic = this->layout_->dynamic_section(); + uint32_t dynamic_addr = dynamic == NULL ? 0 : dynamic->address(); + elfcpp::Swap<32, false>::writeval(got_pov, dynamic_addr); + got_pov += 4; + memset(got_pov, 0, 8); + got_pov += 8; + + const int rel_size = elfcpp::Elf_sizes<32>::rel_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 += this->get_plt_entry_size(), + got_pov += 4, + plt_offset += this->get_plt_entry_size(), + plt_rel_offset += rel_size, + got_offset += 4) + { + // Set and adjust the PLT entry itself. + 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 + lazy_offset); + } + + // If any STT_GNU_IFUNC symbols have PLT entries, we need to change + // the GOT to point to the actual symbol value, rather than point to + // the PLT entry. That will let the dynamic linker call the right + // function when resolving IRELATIVE relocations. + unsigned char* got_irelative_view = got_view + this->got_plt_->data_size(); + for (std::vector::const_iterator p = + this->global_ifuncs_.begin(); + p != this->global_ifuncs_.end(); + ++p) + { + const Sized_symbol<32>* ssym = + static_cast*>(p->sym); + elfcpp::Swap<32, false>::writeval(got_irelative_view + p->got_offset, + ssym->value()); + } + + for (std::vector::const_iterator p = + this->local_ifuncs_.begin(); + p != this->local_ifuncs_.end(); + ++p) + { + const Symbol_value<32>* psymval = + p->object->local_symbol(p->local_sym_index); + elfcpp::Swap<32, false>::writeval(got_irelative_view + p->got_offset, + psymval->value(p->object, 0)); + } + + gold_assert(static_cast(pov - oview) == oview_size); + gold_assert(static_cast(got_pov - got_view) == got_size); + + of->write_output_view(offset, oview_size, oview); + of->write_output_view(got_file_offset, got_size, got_view); +} + +// Create the PLT section. + +void +Target_i386::make_plt_section(Symbol_table* symtab, Layout* layout) +{ + if (this->plt_ == NULL) + { + // Create the GOT sections first. + this->got_section(symtab, layout); + + 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), + this->plt_, ORDER_PLT, false); + + // Make the sh_info field of .rel.plt point to .plt. + Output_section* rel_plt_os = this->plt_->rel_plt()->output_section(); + rel_plt_os->set_info_section(this->plt_->output_section()); + } +} + +// Create a PLT entry for a global symbol. + +void +Target_i386::make_plt_entry(Symbol_table* symtab, Layout* layout, Symbol* gsym) +{ + if (gsym->has_plt_offset()) + return; + if (this->plt_ == NULL) + this->make_plt_section(symtab, layout); + this->plt_->add_entry(symtab, layout, gsym); +} + +// Make a PLT entry for a local STT_GNU_IFUNC symbol. + +void +Target_i386::make_local_ifunc_plt_entry(Symbol_table* symtab, Layout* layout, + Sized_relobj_file<32, false>* relobj, + unsigned int local_sym_index) +{ + if (relobj->local_has_plt_offset(local_sym_index)) + return; + if (this->plt_ == NULL) + this->make_plt_section(symtab, layout); + unsigned int plt_offset = this->plt_->add_local_ifunc_entry(symtab, layout, + relobj, + local_sym_index); + relobj->set_local_plt_offset(local_sym_index, plt_offset); +} + +// Return the number of entries in the PLT. + +unsigned int +Target_i386::plt_entry_count() const +{ + if (this->plt_ == NULL) + return 0; + return this->plt_->entry_count(); +} + +// Return the offset of the first non-reserved PLT entry. + +unsigned int +Target_i386::first_plt_entry_offset() const +{ + return this->plt_->first_plt_entry_offset(); +} + +// Return the size of each PLT entry. + +unsigned int +Target_i386::plt_entry_size() const +{ + return this->plt_->get_plt_entry_size(); +} + +// Get the section to use for TLS_DESC relocations. + +Target_i386::Reloc_section* +Target_i386::rel_tls_desc_section(Layout* layout) const +{ + return this->plt_section()->rel_tls_desc(layout); +} + +// Define the _TLS_MODULE_BASE_ symbol in the TLS segment. + +void +Target_i386::define_tls_base_symbol(Symbol_table* symtab, Layout* layout) +{ + if (this->tls_base_symbol_defined_) + return; + + Output_segment* tls_segment = layout->tls_segment(); + if (tls_segment != NULL) + { + bool is_exec = parameters->options().output_is_executable(); + symtab->define_in_output_segment("_TLS_MODULE_BASE_", NULL, + Symbol_table::PREDEFINED, + tls_segment, 0, 0, + elfcpp::STT_TLS, + elfcpp::STB_LOCAL, + elfcpp::STV_HIDDEN, 0, + (is_exec + ? Symbol::SEGMENT_END + : Symbol::SEGMENT_START), + true); + } + this->tls_base_symbol_defined_ = true; +} + +// Create a GOT entry for the TLS module index. + +unsigned int +Target_i386::got_mod_index_entry(Symbol_table* symtab, Layout* layout, + Sized_relobj_file<32, false>* object) +{ + if (this->got_mod_index_offset_ == -1U) + { + gold_assert(symtab != NULL && layout != NULL && object != NULL); + Reloc_section* rel_dyn = this->rel_dyn_section(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->add_constant(0); + this->got_mod_index_offset_ = got_offset; + } + return this->got_mod_index_offset_; +} + +// Optimize the TLS relocation type based on what we know about the +// symbol. IS_FINAL is true if the final address of this symbol is +// known at link time. + +tls::Tls_optimization +Target_i386::optimize_tls_reloc(bool is_final, int r_type) +{ + // If we are generating a shared library, then we can't do anything + // in the linker. + if (parameters->options().shared()) + return tls::TLSOPT_NONE; + + switch (r_type) + { + case elfcpp::R_386_TLS_GD: + case elfcpp::R_386_TLS_GOTDESC: + case elfcpp::R_386_TLS_DESC_CALL: + // These are General-Dynamic which permits fully general TLS + // access. Since we know that we are generating an executable, + // we can convert this to Initial-Exec. If we also know that + // this is a local symbol, we can further switch to Local-Exec. + if (is_final) + return tls::TLSOPT_TO_LE; + return tls::TLSOPT_TO_IE; + + case elfcpp::R_386_TLS_LDM: + // This is Local-Dynamic, which refers to a local symbol in the + // dynamic TLS block. Since we know that we generating an + // executable, we can switch to Local-Exec. + return tls::TLSOPT_TO_LE; + + case elfcpp::R_386_TLS_LDO_32: + // Another type of Local-Dynamic relocation. + return tls::TLSOPT_TO_LE; + + case elfcpp::R_386_TLS_IE: + case elfcpp::R_386_TLS_GOTIE: + case elfcpp::R_386_TLS_IE_32: + // These are Initial-Exec relocs which get the thread offset + // from the GOT. If we know that we are linking against the + // local symbol, we can switch to Local-Exec, which links the + // thread offset into the instruction. + if (is_final) + return tls::TLSOPT_TO_LE; + return tls::TLSOPT_NONE; + + case elfcpp::R_386_TLS_LE: + case elfcpp::R_386_TLS_LE_32: + // When we already have Local-Exec, there is nothing further we + // can do. + return tls::TLSOPT_NONE; + + default: + gold_unreachable(); + } +} + +// Get the Reference_flags for a particular relocation. + +int +Target_i386::Scan::get_reference_flags(unsigned int r_type) +{ + switch (r_type) + { + case elfcpp::R_386_NONE: + case elfcpp::R_386_GNU_VTINHERIT: + case elfcpp::R_386_GNU_VTENTRY: + case elfcpp::R_386_GOTPC: + // No symbol reference. + return 0; + + case elfcpp::R_386_32: + case elfcpp::R_386_16: + case elfcpp::R_386_8: + return Symbol::ABSOLUTE_REF; + + case elfcpp::R_386_PC32: + case elfcpp::R_386_PC16: + case elfcpp::R_386_PC8: + case elfcpp::R_386_GOTOFF: + return Symbol::RELATIVE_REF; + + case elfcpp::R_386_PLT32: + return Symbol::FUNCTION_CALL | Symbol::RELATIVE_REF; + + case elfcpp::R_386_GOT32: + // Absolute in GOT. + return Symbol::ABSOLUTE_REF; + + case elfcpp::R_386_TLS_GD: // Global-dynamic + case elfcpp::R_386_TLS_GOTDESC: // Global-dynamic (from ~oliva url) + case elfcpp::R_386_TLS_DESC_CALL: + case elfcpp::R_386_TLS_LDM: // Local-dynamic + case elfcpp::R_386_TLS_LDO_32: // Alternate local-dynamic + case elfcpp::R_386_TLS_IE: // Initial-exec + case elfcpp::R_386_TLS_IE_32: + case elfcpp::R_386_TLS_GOTIE: + case elfcpp::R_386_TLS_LE: // Local-exec + case elfcpp::R_386_TLS_LE_32: + return Symbol::TLS_REF; + + case elfcpp::R_386_COPY: + case elfcpp::R_386_GLOB_DAT: + case elfcpp::R_386_JUMP_SLOT: + case elfcpp::R_386_RELATIVE: + case elfcpp::R_386_IRELATIVE: + case elfcpp::R_386_TLS_TPOFF: + case elfcpp::R_386_TLS_DTPMOD32: + case elfcpp::R_386_TLS_DTPOFF32: + case elfcpp::R_386_TLS_TPOFF32: + case elfcpp::R_386_TLS_DESC: + case elfcpp::R_386_32PLT: + case elfcpp::R_386_TLS_GD_32: + case elfcpp::R_386_TLS_GD_PUSH: + case elfcpp::R_386_TLS_GD_CALL: + case elfcpp::R_386_TLS_GD_POP: + case elfcpp::R_386_TLS_LDM_32: + case elfcpp::R_386_TLS_LDM_PUSH: + case elfcpp::R_386_TLS_LDM_CALL: + case elfcpp::R_386_TLS_LDM_POP: + case elfcpp::R_386_USED_BY_INTEL_200: + default: + // Not expected. We will give an error later. + return 0; + } +} + +// Report an unsupported relocation against a local symbol. + +void +Target_i386::Scan::unsupported_reloc_local(Sized_relobj_file<32, false>* object, + unsigned int r_type) +{ + gold_error(_("%s: unsupported reloc %u against local symbol"), + object->name().c_str(), r_type); +} + +// Return whether we need to make a PLT entry for a relocation of a +// given type against a STT_GNU_IFUNC symbol. + +bool +Target_i386::Scan::reloc_needs_plt_for_ifunc( + Sized_relobj_file<32, false>* object, + unsigned int r_type) +{ + 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); + return flags != 0; +} + +// Scan a relocation for a local symbol. + +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, + bool is_discarded) +{ + if (is_discarded) + return; + + // A local STT_GNU_IFUNC symbol may require a PLT entry. + if (lsym.get_st_type() == elfcpp::STT_GNU_IFUNC + && this->reloc_needs_plt_for_ifunc(object, r_type)) + { + unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); + target->make_local_ifunc_plt_entry(symtab, layout, object, r_sym); + } + + switch (r_type) + { + case elfcpp::R_386_NONE: + case elfcpp::R_386_GNU_VTINHERIT: + case elfcpp::R_386_GNU_VTENTRY: + break; + + case elfcpp::R_386_32: + // If building a shared library (or a position-independent + // executable), we need to create a dynamic relocation for + // this location. The relocation applied at link time will + // apply the link-time value, so we flag the location with + // 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()); + 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: + case elfcpp::R_386_8: + // If building a shared library (or a position-independent + // executable), we need to create a dynamic relocation for + // this location. Because the addend needs to remain in the + // 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); + unsigned int r_sym = elfcpp::elf_r_sym<32>(reloc.get_r_info()); + 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); + 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(_("section symbol %u has bad shndx %u"), + r_sym, shndx); + else + rel_dyn->add_local_section(object, shndx, + r_type, output_section, + data_shndx, reloc.get_r_offset()); + } + } + break; + + case elfcpp::R_386_PC32: + case elfcpp::R_386_PC16: + case elfcpp::R_386_PC8: + break; + + case elfcpp::R_386_PLT32: + // Since we know this is a local symbol, we can handle this as a + // PC32 reloc. + break; + + case elfcpp::R_386_GOTOFF: + case elfcpp::R_386_GOTPC: + // We need a GOT section. + target->got_section(symtab, layout); + break; + + 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()); + + // For a STT_GNU_IFUNC symbol we want the PLT offset. That + // lets function pointers compare correctly with shared + // libraries. Otherwise we would need an IRELATIVE reloc. + bool is_new; + if (lsym.get_st_type() == elfcpp::STT_GNU_IFUNC) + 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); + 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; + + // These are relocations which should only be seen by the + // dynamic linker, and should never be seen here. + case elfcpp::R_386_COPY: + case elfcpp::R_386_GLOB_DAT: + case elfcpp::R_386_JUMP_SLOT: + case elfcpp::R_386_RELATIVE: + case elfcpp::R_386_IRELATIVE: + case elfcpp::R_386_TLS_TPOFF: + case elfcpp::R_386_TLS_DTPMOD32: + case elfcpp::R_386_TLS_DTPOFF32: + case elfcpp::R_386_TLS_TPOFF32: + case elfcpp::R_386_TLS_DESC: + gold_error(_("%s: unexpected reloc %u in object file"), + object->name().c_str(), r_type); + break; + + // These are initial TLS relocs, which are expected when + // linking. + case elfcpp::R_386_TLS_GD: // Global-dynamic + case elfcpp::R_386_TLS_GOTDESC: // Global-dynamic (from ~oliva url) + case elfcpp::R_386_TLS_DESC_CALL: + case elfcpp::R_386_TLS_LDM: // Local-dynamic + case elfcpp::R_386_TLS_LDO_32: // Alternate local-dynamic + case elfcpp::R_386_TLS_IE: // Initial-exec + case elfcpp::R_386_TLS_IE_32: + case elfcpp::R_386_TLS_GOTIE: + case elfcpp::R_386_TLS_LE: // Local-exec + case elfcpp::R_386_TLS_LE_32: + { + bool output_is_shared = parameters->options().shared(); + const tls::Tls_optimization optimized_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()); + 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 + got->add_local_pair_with_rel(object, r_sym, shndx, + GOT_TYPE_TLS_PAIR, + target->rel_dyn_section(layout), + elfcpp::R_386_TLS_DTPMOD32); + } + else if (optimized_type != tls::TLSOPT_TO_LE) + unsupported_reloc_local(object, r_type); + break; + + 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. + 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()); + if (!object->local_has_got_offset(r_sym, GOT_TYPE_TLS_DESC)) + { + unsigned int got_offset = got->add_constant(0); + // The local symbol value is stored in the second + // GOT entry. + got->add_local(object, r_sym, GOT_TYPE_TLS_DESC); + // That set the GOT offset of the local symbol to + // point to the second entry, but we want it to + // point to the first. + object->set_local_got_offset(r_sym, GOT_TYPE_TLS_DESC, + got_offset); + 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); + break; + + case elfcpp::R_386_TLS_DESC_CALL: + break; + + 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); + } + else if (optimized_type != tls::TLSOPT_TO_LE) + unsupported_reloc_local(object, r_type); + break; + + case elfcpp::R_386_TLS_LDO_32: // Alternate local-dynamic + break; + + case elfcpp::R_386_TLS_IE: // Initial-exec + case elfcpp::R_386_TLS_IE_32: + case elfcpp::R_386_TLS_GOTIE: + 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); + } + else if (optimized_type != tls::TLSOPT_TO_LE) + unsupported_reloc_local(object, r_type); + break; + + case elfcpp::R_386_TLS_LE: // Local-exec + case elfcpp::R_386_TLS_LE_32: + 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()); + } + break; + + default: + gold_unreachable(); + } + } + break; + + case elfcpp::R_386_32PLT: + case elfcpp::R_386_TLS_GD_32: + case elfcpp::R_386_TLS_GD_PUSH: + case elfcpp::R_386_TLS_GD_CALL: + case elfcpp::R_386_TLS_GD_POP: + case elfcpp::R_386_TLS_LDM_32: + case elfcpp::R_386_TLS_LDM_PUSH: + case elfcpp::R_386_TLS_LDM_CALL: + case elfcpp::R_386_TLS_LDM_POP: + case elfcpp::R_386_USED_BY_INTEL_200: + default: + unsupported_reloc_local(object, r_type); + break; + } +} + +// Report an unsupported relocation against a global symbol. + +void +Target_i386::Scan::unsupported_reloc_global( + Sized_relobj_file<32, false>* object, + unsigned int r_type, + Symbol* gsym) +{ + gold_error(_("%s: unsupported reloc %u against global symbol %s"), + object->name().c_str(), r_type, gsym->demangled_name().c_str()); +} + +inline bool +Target_i386::Scan::possible_function_pointer_reloc(unsigned int r_type) +{ + switch (r_type) + { + case elfcpp::R_386_32: + case elfcpp::R_386_16: + case elfcpp::R_386_8: + case elfcpp::R_386_GOTOFF: + case elfcpp::R_386_GOT32: + { + return true; + } + default: + return false; + } + return false; +} + +inline bool +Target_i386::Scan::local_reloc_may_be_function_pointer( + Symbol_table* , + Layout* , + Target_i386* , + Sized_relobj_file<32, false>* , + unsigned int , + Output_section* , + const elfcpp::Rel<32, false>& , + unsigned int r_type, + const elfcpp::Sym<32, false>&) +{ + return possible_function_pointer_reloc(r_type); +} + +inline bool +Target_i386::Scan::global_reloc_may_be_function_pointer( + Symbol_table* , + Layout* , + Target_i386* , + Sized_relobj_file<32, false>* , + unsigned int , + Output_section* , + const elfcpp::Rel<32, false>& , + unsigned int r_type, + Symbol*) +{ + return possible_function_pointer_reloc(r_type); +} + +// Scan a relocation for a global symbol. + +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) +{ + // A STT_GNU_IFUNC symbol may require a PLT entry. + if (gsym->type() == elfcpp::STT_GNU_IFUNC + && this->reloc_needs_plt_for_ifunc(object, r_type)) + target->make_plt_entry(symtab, layout, gsym); + + switch (r_type) + { + case elfcpp::R_386_NONE: + case elfcpp::R_386_GNU_VTINHERIT: + case elfcpp::R_386_GNU_VTENTRY: + break; + + case elfcpp::R_386_32: + 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); + } + else if (r_type == elfcpp::R_386_32 + && gsym->type() == elfcpp::STT_GNU_IFUNC + && gsym->can_use_relative_reloc(false) + && !gsym->is_from_dynobj() + && !gsym->is_undefined() + && !gsym->is_preemptible()) + { + // Use an IRELATIVE reloc for a locally defined + // STT_GNU_IFUNC symbol. This makes a function + // address in a PIE executable match the address in a + // shared library that it links against. + Reloc_section* rel_dyn = target->rel_irelative_section(layout); + rel_dyn->add_symbolless_global_addend(gsym, + elfcpp::R_386_IRELATIVE, + output_section, + 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); + 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()); + } + } + } + break; + + case elfcpp::R_386_PC32: + 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()); + } + } + } + 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()) + { + // For a STT_GNU_IFUNC symbol we want the PLT address. + if (gsym->type() == elfcpp::STT_GNU_IFUNC) + got->add_global_plt(gsym, GOT_TYPE_STANDARD); + 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); + + // Use a GLOB_DAT rather than a RELATIVE reloc if: + // + // 1) The symbol may be defined in some other module. + // + // 2) We are building a shared library and this is a + // protected symbol; using GLOB_DAT means that the dynamic + // linker can use the address of the PLT in the main + // executable when appropriate so that function address + // comparisons work. + // + // 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() + || (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 + { + // For a STT_GNU_IFUNC symbol we want to write the PLT + // offset into the GOT, so that function pointer + // comparisons work correctly. + bool is_new; + if (gsym->type() != elfcpp::STT_GNU_IFUNC) + is_new = got->add_global(gsym, GOT_TYPE_STANDARD); + else + { + is_new = got->add_global_plt(gsym, GOT_TYPE_STANDARD); + // Tell the dynamic linker to use the PLT address + // when resolving relocations. + if (gsym->is_from_dynobj() + && !parameters->options().shared()) + gsym->set_needs_dynsym_value(); + } + 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; + + case elfcpp::R_386_PLT32: + // If the symbol is fully resolved, this is just a PC32 reloc. + // Otherwise we need a PLT entry. + if (gsym->final_value_is_known()) + break; + // If building a shared library, we can also skip the PLT entry + // 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()) + break; + target->make_plt_entry(symtab, layout, gsym); + break; + + case elfcpp::R_386_GOTOFF: + case elfcpp::R_386_GOTPC: + // We need a GOT section. + target->got_section(symtab, layout); + break; + + // These are relocations which should only be seen by the + // dynamic linker, and should never be seen here. + case elfcpp::R_386_COPY: + case elfcpp::R_386_GLOB_DAT: + case elfcpp::R_386_JUMP_SLOT: + case elfcpp::R_386_RELATIVE: + case elfcpp::R_386_IRELATIVE: + case elfcpp::R_386_TLS_TPOFF: + case elfcpp::R_386_TLS_DTPMOD32: + case elfcpp::R_386_TLS_DTPOFF32: + case elfcpp::R_386_TLS_TPOFF32: + case elfcpp::R_386_TLS_DESC: + gold_error(_("%s: unexpected reloc %u in object file"), + object->name().c_str(), r_type); + break; + + // These are initial tls relocs, which are expected when + // linking. + case elfcpp::R_386_TLS_GD: // Global-dynamic + case elfcpp::R_386_TLS_GOTDESC: // Global-dynamic (from ~oliva url) + case elfcpp::R_386_TLS_DESC_CALL: + case elfcpp::R_386_TLS_LDM: // Local-dynamic + case elfcpp::R_386_TLS_LDO_32: // Alternate local-dynamic + case elfcpp::R_386_TLS_IE: // Initial-exec + case elfcpp::R_386_TLS_IE_32: + case elfcpp::R_386_TLS_GOTIE: + case elfcpp::R_386_TLS_LE: // Local-exec + case elfcpp::R_386_TLS_LE_32: + { + const bool is_final = gsym->final_value_is_known(); + const tls::Tls_optimization optimized_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); + } + 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_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. + target->got_section(symtab, layout); + 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); + break; + + case elfcpp::R_386_TLS_DESC_CALL: + break; + + 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); + } + else if (optimized_type != tls::TLSOPT_TO_LE) + unsupported_reloc_global(object, r_type, gsym); + break; + + case elfcpp::R_386_TLS_LDO_32: // Alternate local-dynamic + break; + + case elfcpp::R_386_TLS_IE: // Initial-exec + case elfcpp::R_386_TLS_IE_32: + case elfcpp::R_386_TLS_GOTIE: + 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); + } + else if (optimized_type != tls::TLSOPT_TO_LE) + unsupported_reloc_global(object, r_type, gsym); + break; + + case elfcpp::R_386_TLS_LE: // Local-exec + case elfcpp::R_386_TLS_LE_32: + 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()); + } + break; + + default: + gold_unreachable(); + } + } + break; + + case elfcpp::R_386_32PLT: + case elfcpp::R_386_TLS_GD_32: + case elfcpp::R_386_TLS_GD_PUSH: + case elfcpp::R_386_TLS_GD_CALL: + case elfcpp::R_386_TLS_GD_POP: + case elfcpp::R_386_TLS_LDM_32: + case elfcpp::R_386_TLS_LDM_PUSH: + case elfcpp::R_386_TLS_LDM_CALL: + case elfcpp::R_386_TLS_LDM_POP: + case elfcpp::R_386_USED_BY_INTEL_200: + default: + unsupported_reloc_global(object, r_type, gsym); + break; + } +} + +// Process relocations for gc. + +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) +{ + gold::gc_process_relocs<32, false, Target_i386, elfcpp::SHT_REL, + Target_i386::Scan, + Target_i386::Relocatable_size_for_reloc>( + symtab, + layout, + this, + object, + data_shndx, + prelocs, + reloc_count, + output_section, + needs_special_offset_handling, + local_symbol_count, + plocal_symbols); +} + +// Scan relocations for a section. + +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) +{ + if (sh_type == elfcpp::SHT_RELA) + { + gold_error(_("%s: unsupported RELA reloc section"), + object->name().c_str()); + return; + } + + gold::scan_relocs<32, false, Target_i386, elfcpp::SHT_REL, + Target_i386::Scan>( + symtab, + layout, + this, + object, + data_shndx, + prelocs, + reloc_count, + output_section, + needs_special_offset_handling, + local_symbol_count, + plocal_symbols); +} + +// Finalize the sections. + +void +Target_i386::do_finalize_sections( + Layout* layout, + const Input_objects*, + Symbol_table* symtab) +{ + const Reloc_section* rel_plt = (this->plt_ == NULL + ? NULL + : this->plt_->rel_plt()); + layout->add_target_dynamic_tags(true, this->got_plt_, rel_plt, + this->rel_dyn_, true, false); + + // Emit any relocs we saved in an attempt to avoid generating COPY + // relocs. + if (this->copy_relocs_.any_saved_relocs()) + this->copy_relocs_.emit(this->rel_dyn_section(layout)); + + // Set the size of the _GLOBAL_OFFSET_TABLE_ symbol to the size of + // the .got.plt section. + Symbol* sym = this->global_offset_table_; + if (sym != NULL) + { + uint32_t data_size = this->got_plt_->current_data_size(); + symtab->get_sized_symbol<32>(sym)->set_symsize(data_size); + } + + if (parameters->doing_static_link() + && (this->plt_ == NULL || !this->plt_->has_irelative_section())) + { + // If linking statically, make sure that the __rel_iplt symbols + // were defined if necessary, even if we didn't create a PLT. + static const Define_symbol_in_segment syms[] = + { + { + "__rel_iplt_start", // name + elfcpp::PT_LOAD, // segment_type + elfcpp::PF_W, // segment_flags_set + elfcpp::PF(0), // segment_flags_clear + 0, // value + 0, // size + elfcpp::STT_NOTYPE, // type + elfcpp::STB_GLOBAL, // binding + elfcpp::STV_HIDDEN, // visibility + 0, // nonvis + Symbol::SEGMENT_START, // offset_from_base + true // only_if_ref + }, + { + "__rel_iplt_end", // name + elfcpp::PT_LOAD, // segment_type + elfcpp::PF_W, // segment_flags_set + elfcpp::PF(0), // segment_flags_clear + 0, // value + 0, // size + elfcpp::STT_NOTYPE, // type + elfcpp::STB_GLOBAL, // binding + elfcpp::STV_HIDDEN, // visibility + 0, // nonvis + Symbol::SEGMENT_START, // offset_from_base + true // only_if_ref + } + }; + + symtab->define_symbols(layout, 2, syms, + layout->script_options()->saw_sections_clause()); + } +} + +// Return whether a direct absolute static relocation needs to be applied. +// In cases where Scan::local() or Scan::global() has created +// a dynamic relocation other than R_386_RELATIVE, the addend +// of the relocation is carried in the data, and we must not +// apply the static relocation. + +inline bool +Target_i386::Relocate::should_apply_static_reloc(const Sized_symbol<32>* gsym, + unsigned int r_type, + bool is_32bit, + Output_section* output_section) +{ + // If the output section is not allocated, then we didn't call + // scan_relocs, we didn't create a dynamic reloc, and we must apply + // the reloc here. + if ((output_section->flags() & elfcpp::SHF_ALLOC) == 0) + return true; + + int ref_flags = Scan::get_reference_flags(r_type); + + // For local symbols, we will have created a non-RELATIVE dynamic + // relocation only if (a) the output is position independent, + // (b) the relocation is absolute (not pc- or segment-relative), and + // (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); + + // 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 + // created a RELATIVE dynamic relocation, we should apply the static + // 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); + return !has_dyn || is_rel; +} + +// Perform a relocation. + +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) +{ + if (this->skip_call_tls_get_addr_) + { + if ((r_type != elfcpp::R_386_PLT32 + && 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(), + _("missing expected TLS relocation")); + else + { + this->skip_call_tls_get_addr_ = false; + return false; + } + } + + if (view == NULL) + return true; + + const Sized_relobj_file<32, false>* object = relinfo->object; + + // Pick the value to use for symbols defined in shared objects. + Symbol_value<32> symval; + if (gsym != NULL + && gsym->type() == elfcpp::STT_GNU_IFUNC + && r_type == elfcpp::R_386_32 + && gsym->needs_dynamic_reloc(Scan::get_reference_flags(r_type)) + && gsym->can_use_relative_reloc(false) + && !gsym->is_from_dynobj() + && !gsym->is_undefined() + && !gsym->is_preemptible()) + { + // In this case we are generating a R_386_IRELATIVE reloc. We + // want to use the real value of the symbol, not the PLT offset. + } + else if (gsym != NULL + && gsym->use_plt_offset(Scan::get_reference_flags(r_type))) + { + symval.set_output_value(target->plt_address_for_global(gsym)); + psymval = &symval; + } + else if (gsym == NULL && psymval->is_ifunc_symbol()) + { + unsigned int r_sym = elfcpp::elf_r_sym<32>(rel.get_r_info()); + if (object->local_has_plt_offset(r_sym)) + { + symval.set_output_value(target->plt_address_for_local(object, r_sym)); + psymval = &symval; + } + } + + // Get the GOT offset if needed. + // The GOT pointer points to the end of the GOT section. + // We need to subtract the size of the GOT section to get + // the actual offset to use in the relocation. + bool have_got_offset = false; + unsigned int got_offset = 0; + switch (r_type) + { + 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()); + } + 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()); + } + have_got_offset = true; + break; + + default: + break; + } + + switch (r_type) + { + case elfcpp::R_386_NONE: + case elfcpp::R_386_GNU_VTINHERIT: + case elfcpp::R_386_GNU_VTENTRY: + break; + + case elfcpp::R_386_32: + if (should_apply_static_reloc(gsym, r_type, true, output_section)) + Relocate_functions<32, false>::rel32(view, object, psymval); + 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); + 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); + 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); + 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); + 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); + break; + + case elfcpp::R_386_PLT32: + gold_assert(gsym == NULL + || gsym->has_plt_offset() + || gsym->final_value_is_known() + || (gsym->is_defined() + && !gsym->is_from_dynobj() + && !gsym->is_preemptible())); + Relocate_functions<32, false>::pcrel32(view, object, psymval, address); + break; + + case elfcpp::R_386_GOT32: + gold_assert(have_got_offset); + Relocate_functions<32, false>::rel32(view, got_offset); + break; + + case elfcpp::R_386_GOTOFF: + { + elfcpp::Elf_types<32>::Elf_Addr value; + value = (psymval->value(object, 0) + - target->got_plt_section()->address()); + Relocate_functions<32, false>::rel32(view, value); + } + break; + + case elfcpp::R_386_GOTPC: + { + elfcpp::Elf_types<32>::Elf_Addr value; + value = target->got_plt_section()->address(); + Relocate_functions<32, false>::pcrel32(view, value, address); + } + break; + + case elfcpp::R_386_COPY: + case elfcpp::R_386_GLOB_DAT: + case elfcpp::R_386_JUMP_SLOT: + case elfcpp::R_386_RELATIVE: + case elfcpp::R_386_IRELATIVE: + // These are outstanding tls relocs, which are unexpected when + // linking. + case elfcpp::R_386_TLS_TPOFF: + case elfcpp::R_386_TLS_DTPMOD32: + case elfcpp::R_386_TLS_DTPOFF32: + case elfcpp::R_386_TLS_TPOFF32: + case elfcpp::R_386_TLS_DESC: + gold_error_at_location(relinfo, relnum, rel.get_r_offset(), + _("unexpected reloc %u in object file"), + r_type); + break; + + // These are initial tls relocs, which are expected when + // linking. + case elfcpp::R_386_TLS_GD: // Global-dynamic + case elfcpp::R_386_TLS_GOTDESC: // Global-dynamic (from ~oliva url) + case elfcpp::R_386_TLS_DESC_CALL: + case elfcpp::R_386_TLS_LDM: // Local-dynamic + case elfcpp::R_386_TLS_LDO_32: // Alternate local-dynamic + case elfcpp::R_386_TLS_IE: // Initial-exec + case elfcpp::R_386_TLS_IE_32: + case elfcpp::R_386_TLS_GOTIE: + 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); + break; + + case elfcpp::R_386_32PLT: + case elfcpp::R_386_TLS_GD_32: + case elfcpp::R_386_TLS_GD_PUSH: + case elfcpp::R_386_TLS_GD_CALL: + case elfcpp::R_386_TLS_GD_POP: + case elfcpp::R_386_TLS_LDM_32: + case elfcpp::R_386_TLS_LDM_PUSH: + case elfcpp::R_386_TLS_LDM_CALL: + case elfcpp::R_386_TLS_LDM_POP: + case elfcpp::R_386_USED_BY_INTEL_200: + default: + gold_error_at_location(relinfo, relnum, rel.get_r_offset(), + _("unsupported reloc %u"), + r_type); + break; + } + + return true; +} + +// Perform a TLS relocation. + +inline void +Target_i386::Relocate::relocate_tls(const Relocate_info<32, false>* relinfo, + Target_i386* target, + 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, + section_size_type view_size) +{ + Output_segment* tls_segment = relinfo->layout->tls_segment(); + + const Sized_relobj_file<32, false>* object = relinfo->object; + + elfcpp::Elf_types<32>::Elf_Addr value = psymval->value(object, 0); + + const bool is_final = (gsym == NULL + ? !parameters->options().shared() + : gsym->final_value_is_known()); + const tls::Tls_optimization optimized_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_TO_LE) + { + if (tls_segment == NULL) + { + gold_assert(parameters->errors()->error_count() > 0 + || issue_undefined_symbol_error(gsym)); + return; + } + this->tls_gd_to_le(relinfo, relnum, tls_segment, + 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_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) + { + this->tls_gd_to_ie(relinfo, relnum, tls_segment, rel, r_type, + 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; + } + } + gold_error_at_location(relinfo, relnum, rel.get_r_offset(), + _("unsupported reloc %u"), + r_type); + break; + + case elfcpp::R_386_TLS_GOTDESC: // Global-dynamic (from ~oliva url) + 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 + || issue_undefined_symbol_error(gsym)); + return; + } + this->tls_desc_gd_to_le(relinfo, relnum, tls_segment, + 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; + if (r_type == elfcpp::R_386_TLS_GOTDESC + && optimized_type == tls::TLSOPT_NONE) + { + // We created GOT entries in the .got.tlsdesc portion of + // the .got.plt section, but the offset stored in the + // symbol is the offset within .got.tlsdesc. + 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) + - target->got_size()); + } + if (optimized_type == tls::TLSOPT_TO_IE) + { + if (tls_segment == NULL) + { + gold_assert(parameters->errors()->error_count() > 0 + || issue_undefined_symbol_error(gsym)); + return; + } + this->tls_desc_gd_to_ie(relinfo, relnum, tls_segment, rel, r_type, + 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; + } + } + gold_error_at_location(relinfo, relnum, rel.get_r_offset(), + _("unsupported reloc %u"), + r_type); + break; + + case elfcpp::R_386_TLS_LDM: // Local-dynamic + if (this->local_dynamic_type_ == LOCAL_DYNAMIC_SUN) + { + gold_error_at_location(relinfo, relnum, rel.get_r_offset(), + _("both SUN and GNU model " + "TLS relocations")); + break; + } + 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 + || issue_undefined_symbol_error(gsym)); + return; + } + this->tls_ld_to_le(relinfo, relnum, tls_segment, rel, 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) + - 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); + break; + + case elfcpp::R_386_TLS_LDO_32: // Alternate local-dynamic + if (optimized_type == tls::TLSOPT_TO_LE) + { + // This reloc can appear in debugging sections, in which + // case we must not convert to local-exec. We decide what + // to do based on whether the section is marked as + // containing executable code. That is what the GNU linker + // does as well. + elfcpp::Shdr<32, false> shdr(relinfo->data_shdr); + if ((shdr.get_sh_flags() & elfcpp::SHF_EXECINSTR) != 0) + { + 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); + break; + + case elfcpp::R_386_TLS_IE: // Initial-exec + case elfcpp::R_386_TLS_GOTIE: + case elfcpp::R_386_TLS_IE_32: + if (optimized_type == tls::TLSOPT_TO_LE) + { + if (tls_segment == NULL) + { + gold_assert(parameters->errors()->error_count() > 0 + || issue_undefined_symbol_error(gsym)); + return; + } + Target_i386::Relocate::tls_ie_to_le(relinfo, relnum, tls_segment, + rel, 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 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; + } + gold_error_at_location(relinfo, relnum, rel.get_r_offset(), + _("unsupported reloc %u"), + r_type); + break; + + case elfcpp::R_386_TLS_LE: // 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()) + { + 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); + } + 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); + } + break; + } +} + +// Do a relocation in which we convert a TLS General-Dynamic to a +// Local-Exec. + +inline void +Target_i386::Relocate::tls_gd_to_le(const Relocate_info<32, false>* relinfo, + size_t relnum, + Output_segment* tls_segment, + const elfcpp::Rel<32, false>& rel, + unsigned int, + elfcpp::Elf_types<32>::Elf_Addr value, + unsigned char* view, + section_size_type view_size) +{ + // leal foo(,%reg,1),%eax; call ___tls_get_addr + // ==> movl %gs:0,%eax; subl $foo@tpoff,%eax + // leal foo(%reg),%eax; call ___tls_get_addr + // ==> movl %gs:0,%eax; subl $foo@tpoff,%eax + + tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, -2); + tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, 9); + + unsigned char op1 = view[-1]; + unsigned char op2 = view[-2]; + + tls::check_tls(relinfo, relnum, rel.get_r_offset(), + op2 == 0x8d || op2 == 0x04); + tls::check_tls(relinfo, relnum, rel.get_r_offset(), view[4] == 0xe8); + + int roff = 5; + + if (op2 == 0x04) + { + 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))); + 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); + if (rel.get_r_offset() + 9 < view_size + && 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); + roff = 6; + } + else + { + // Use the five byte subl. + memcpy(view - 2, "\x65\xa1\0\0\0\0\x2d\0\0\0", 11); + } + } + + value = tls_segment->memsz() - value; + Relocate_functions<32, false>::rel32(view + roff, value); + + // The next reloc should be a PLT32 reloc against __tls_get_addr. + // We can skip it. + this->skip_call_tls_get_addr_ = true; +} + +// Do a relocation in which we convert a TLS General-Dynamic to an +// Initial-Exec. + +inline void +Target_i386::Relocate::tls_gd_to_ie(const Relocate_info<32, false>* relinfo, + size_t relnum, + Output_segment*, + const elfcpp::Rel<32, false>& rel, + unsigned int, + elfcpp::Elf_types<32>::Elf_Addr value, + unsigned char* view, + section_size_type view_size) +{ + // leal foo(,%ebx,1),%eax; call ___tls_get_addr + // ==> movl %gs:0,%eax; addl foo@gotntpoff(%ebx),%eax + + tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, -2); + tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, 9); + + unsigned char op1 = view[-1]; + unsigned char op2 = view[-2]; + + tls::check_tls(relinfo, relnum, rel.get_r_offset(), + op2 == 0x8d || op2 == 0x04); + tls::check_tls(relinfo, relnum, rel.get_r_offset(), view[4] == 0xe8); + + int roff = 5; + + // FIXME: For now, support only the first (SIB) form. + tls::check_tls(relinfo, relnum, rel.get_r_offset(), op2 == 0x04); + + if (op2 == 0x04) + { + 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))); + 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); + if (rel.get_r_offset() + 9 < view_size + && view[9] == 0x90) + { + // 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. + // Use the five byte subl. + memcpy(view - 2, "\x65\xa1\0\0\0\0\x2d\0\0\0", 11); + } + } + + Relocate_functions<32, false>::rel32(view + roff, value); + + // The next reloc should be a PLT32 reloc against __tls_get_addr. + // We can skip it. + this->skip_call_tls_get_addr_ = true; +} + +// Do a relocation in which we convert a TLS_GOTDESC or TLS_DESC_CALL +// General-Dynamic to a Local-Exec. + +inline void +Target_i386::Relocate::tls_desc_gd_to_le( + const Relocate_info<32, false>* relinfo, + size_t relnum, + Output_segment* tls_segment, + const elfcpp::Rel<32, false>& rel, + unsigned int r_type, + elfcpp::Elf_types<32>::Elf_Addr value, + unsigned char* view, + section_size_type view_size) +{ + if (r_type == elfcpp::R_386_TLS_GOTDESC) + { + // leal foo@TLSDESC(%ebx), %eax + // ==> leal foo@NTPOFF, %eax + 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[-1] = 0x05; + value -= tls_segment->memsz(); + Relocate_functions<32, false>::rel32(view, value); + } + else + { + // call *foo@TLSCALL(%eax) + // ==> nop; nop + 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] = 0x66; + view[1] = 0x90; + } +} + +// Do a relocation in which we convert a TLS_GOTDESC or TLS_DESC_CALL +// General-Dynamic to an Initial-Exec. + +inline void +Target_i386::Relocate::tls_desc_gd_to_ie( + const Relocate_info<32, false>* relinfo, + size_t relnum, + Output_segment*, + const elfcpp::Rel<32, false>& rel, + unsigned int r_type, + elfcpp::Elf_types<32>::Elf_Addr value, + unsigned char* view, + section_size_type view_size) +{ + if (r_type == elfcpp::R_386_TLS_GOTDESC) + { + // leal foo@TLSDESC(%ebx), %eax + // ==> movl foo@GOTNTPOFF(%ebx), %eax + 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] = 0x8b; + Relocate_functions<32, false>::rel32(view, value); + } + else + { + // call *foo@TLSCALL(%eax) + // ==> nop; nop + 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] = 0x66; + view[1] = 0x90; + } +} + +// Do a relocation in which we convert a TLS Local-Dynamic to a +// Local-Exec. + +inline void +Target_i386::Relocate::tls_ld_to_le(const Relocate_info<32, false>* relinfo, + size_t relnum, + Output_segment*, + const elfcpp::Rel<32, false>& rel, + unsigned int, + elfcpp::Elf_types<32>::Elf_Addr, + unsigned char* view, + section_size_type view_size) +{ + // leal foo(%reg), %eax; call ___tls_get_addr + // ==> movl %gs:0,%eax; nop; leal 0(%esi,1),%esi + + tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, -2); + tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, 9); + + // FIXME: Does this test really always pass? + tls::check_tls(relinfo, relnum, rel.get_r_offset(), + view[-2] == 0x8d && view[-1] == 0x83); + + tls::check_tls(relinfo, relnum, rel.get_r_offset(), view[4] == 0xe8); + + memcpy(view - 2, "\x65\xa1\0\0\0\0\x90\x8d\x74\x26\0", 11); + + // The next reloc should be a PLT32 reloc against __tls_get_addr. + // We can skip it. + this->skip_call_tls_get_addr_ = true; +} + +// Do a relocation in which we convert a TLS Initial-Exec to a +// Local-Exec. + +inline void +Target_i386::Relocate::tls_ie_to_le(const Relocate_info<32, false>* relinfo, + size_t relnum, + Output_segment* tls_segment, + const elfcpp::Rel<32, false>& rel, + unsigned int r_type, + elfcpp::Elf_types<32>::Elf_Addr value, + unsigned char* view, + section_size_type view_size) +{ + // We have to actually change the instructions, which means that we + // need to examine the opcodes to figure out which instruction we + // are looking at. + if (r_type == elfcpp::R_386_TLS_IE) + { + // movl %gs:XX,%eax ==> movl $YY,%eax + // movl %gs:XX,%reg ==> movl $YY,%reg + // addl %gs:XX,%reg ==> addl $YY,%reg + tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, -1); + tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, 4); + + unsigned char op1 = view[-1]; + if (op1 == 0xa1) + { + // movl XX,%eax ==> movl $YY,%eax + view[-1] = 0xb8; + } + else + { + tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, -2); + + unsigned char op2 = view[-2]; + if (op2 == 0x8b) + { + // movl XX,%reg ==> movl $YY,%reg + tls::check_tls(relinfo, relnum, rel.get_r_offset(), + (op1 & 0xc7) == 0x05); + view[-2] = 0xc7; + view[-1] = 0xc0 | ((op1 >> 3) & 7); + } + else if (op2 == 0x03) + { + // addl XX,%reg ==> addl $YY,%reg + tls::check_tls(relinfo, relnum, rel.get_r_offset(), + (op1 & 0xc7) == 0x05); + view[-2] = 0x81; + view[-1] = 0xc0 | ((op1 >> 3) & 7); + } + else + tls::check_tls(relinfo, relnum, rel.get_r_offset(), 0); + } + } + else + { + // subl %gs:XX(%reg1),%reg2 ==> subl $YY,%reg2 + // movl %gs:XX(%reg1),%reg2 ==> movl $YY,%reg2 + // addl %gs:XX(%reg1),%reg2 ==> addl $YY,$reg2 + tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, -2); + tls::check_range(relinfo, relnum, rel.get_r_offset(), view_size, 4); + + 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); + if (op2 == 0x8b) + { + // movl %gs:XX(%reg1),%reg2 ==> movl $YY,%reg2 + view[-2] = 0xc7; + view[-1] = 0xc0 | ((op1 >> 3) & 7); + } + else if (op2 == 0x2b) + { + // subl %gs:XX(%reg1),%reg2 ==> subl $YY,%reg2 + view[-2] = 0x81; + view[-1] = 0xe8 | ((op1 >> 3) & 7); + } + else if (op2 == 0x03) + { + // addl %gs:XX(%reg1),%reg2 ==> addl $YY,$reg2 + view[-2] = 0x81; + view[-1] = 0xc0 | ((op1 >> 3) & 7); + } + else + tls::check_tls(relinfo, relnum, rel.get_r_offset(), 0); + } + + value = tls_segment->memsz() - value; + if (r_type == elfcpp::R_386_TLS_IE || r_type == elfcpp::R_386_TLS_GOTIE) + value = - value; + + Relocate_functions<32, false>::rel32(view, value); +} + +// Relocate section data. + +void +Target_i386::relocate_section(const Relocate_info<32, false>* relinfo, + unsigned int sh_type, + const unsigned char* prelocs, + size_t reloc_count, + Output_section* output_section, + bool needs_special_offset_handling, + unsigned char* view, + elfcpp::Elf_types<32>::Elf_Addr address, + section_size_type view_size, + const Reloc_symbol_changes* reloc_symbol_changes) +{ + gold_assert(sh_type == elfcpp::SHT_REL); + + gold::relocate_section<32, false, Target_i386, elfcpp::SHT_REL, + Target_i386::Relocate, gold::Default_comdat_behavior>( + relinfo, + this, + prelocs, + reloc_count, + output_section, + needs_special_offset_handling, + view, + address, + view_size, + reloc_symbol_changes); +} + +// Return the size of a relocation while scanning during a relocatable +// link. + +unsigned int +Target_i386::Relocatable_size_for_reloc::get_size_for_reloc( + unsigned int r_type, + Relobj* object) +{ + switch (r_type) + { + case elfcpp::R_386_NONE: + case elfcpp::R_386_GNU_VTINHERIT: + case elfcpp::R_386_GNU_VTENTRY: + case elfcpp::R_386_TLS_GD: // Global-dynamic + case elfcpp::R_386_TLS_GOTDESC: // Global-dynamic (from ~oliva url) + case elfcpp::R_386_TLS_DESC_CALL: + case elfcpp::R_386_TLS_LDM: // Local-dynamic + case elfcpp::R_386_TLS_LDO_32: // Alternate local-dynamic + case elfcpp::R_386_TLS_IE: // Initial-exec + case elfcpp::R_386_TLS_IE_32: + case elfcpp::R_386_TLS_GOTIE: + case elfcpp::R_386_TLS_LE: // Local-exec + case elfcpp::R_386_TLS_LE_32: + return 0; + + case elfcpp::R_386_32: + case elfcpp::R_386_PC32: + case elfcpp::R_386_GOT32: + case elfcpp::R_386_PLT32: + case elfcpp::R_386_GOTOFF: + case elfcpp::R_386_GOTPC: + return 4; + + case elfcpp::R_386_16: + case elfcpp::R_386_PC16: + return 2; + + case elfcpp::R_386_8: + case elfcpp::R_386_PC8: + return 1; + + // These are relocations which should only be seen by the + // dynamic linker, and should never be seen here. + case elfcpp::R_386_COPY: + case elfcpp::R_386_GLOB_DAT: + case elfcpp::R_386_JUMP_SLOT: + case elfcpp::R_386_RELATIVE: + case elfcpp::R_386_IRELATIVE: + case elfcpp::R_386_TLS_TPOFF: + case elfcpp::R_386_TLS_DTPMOD32: + case elfcpp::R_386_TLS_DTPOFF32: + case elfcpp::R_386_TLS_TPOFF32: + case elfcpp::R_386_TLS_DESC: + object->error(_("unexpected reloc %u in object file"), r_type); + return 0; + + case elfcpp::R_386_32PLT: + case elfcpp::R_386_TLS_GD_32: + case elfcpp::R_386_TLS_GD_PUSH: + case elfcpp::R_386_TLS_GD_CALL: + case elfcpp::R_386_TLS_GD_POP: + case elfcpp::R_386_TLS_LDM_32: + case elfcpp::R_386_TLS_LDM_PUSH: + case elfcpp::R_386_TLS_LDM_CALL: + case elfcpp::R_386_TLS_LDM_POP: + case elfcpp::R_386_USED_BY_INTEL_200: + default: + object->error(_("unsupported reloc %u in object file"), r_type); + return 0; + } +} + +// Scan the relocs during a relocatable link. + +void +Target_i386::scan_relocatable_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, + Relocatable_relocs* rr) +{ + gold_assert(sh_type == elfcpp::SHT_REL); + + typedef gold::Default_scan_relocatable_relocs Scan_relocatable_relocs; + + gold::scan_relocatable_relocs<32, false, elfcpp::SHT_REL, + Scan_relocatable_relocs>( + symtab, + layout, + object, + data_shndx, + prelocs, + reloc_count, + output_section, + needs_special_offset_handling, + local_symbol_count, + plocal_symbols, + rr); +} + +// Emit relocations for a section. + +void +Target_i386::relocate_relocs( + const Relocate_info<32, false>* relinfo, + unsigned int sh_type, + const unsigned char* prelocs, + size_t reloc_count, + Output_section* output_section, + elfcpp::Elf_types<32>::Elf_Off offset_in_output_section, + const Relocatable_relocs* rr, + unsigned char* view, + elfcpp::Elf_types<32>::Elf_Addr view_address, + section_size_type view_size, + unsigned char* reloc_view, + section_size_type reloc_view_size) +{ + gold_assert(sh_type == elfcpp::SHT_REL); + + gold::relocate_relocs<32, false, elfcpp::SHT_REL>( + relinfo, + prelocs, + reloc_count, + output_section, + offset_in_output_section, + rr, + view, + view_address, + view_size, + reloc_view, + reloc_view_size); +} + +// Return the value to use for a dynamic which requires special +// treatment. This is how we support equality comparisons of function +// pointers across shared library boundaries, as described in the +// processor specific ABI supplement. + +uint64_t +Target_i386::do_dynsym_value(const Symbol* gsym) const +{ + gold_assert(gsym->is_from_dynobj() && gsym->has_plt_offset()); + return this->plt_address_for_global(gsym); +} + +// Return a string used to fill a code section with nops to take up +// the specified length. + +std::string +Target_i386::do_code_fill(section_size_type length) const +{ + if (length >= 16) + { + // Build a jmp instruction to skip over the bytes. + unsigned char jmp[5]; + jmp[0] = 0xe9; + elfcpp::Swap_unaligned<32, false>::writeval(jmp + 1, length - 5); + return (std::string(reinterpret_cast(&jmp[0]), 5) + + std::string(length - 5, static_cast(0x90))); + } + + // Nop sequences of various lengths. + const char nop1[1] = { '\x90' }; // nop + const char nop2[2] = { '\x66', '\x90' }; // xchg %ax %ax + const char nop3[3] = { '\x8d', '\x76', '\x00' }; // leal 0(%esi),%esi + 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 + const char nop6[6] = { '\x8d', '\xb6', '\x00', // leal 0L(%esi),%esi + '\x00', '\x00', '\x00' }; + const char nop7[7] = { '\x8d', '\xb4', '\x26', // leal 0L(%esi,1),%esi + '\x00', '\x00', '\x00', + '\x00' }; + const char nop8[8] = { '\x90', '\x8d', '\xb4', // nop + '\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 + '\x00', '\x00', '\x00' }; + const char nop10[10] = { '\x8d', '\x76', '\x00', // leal 0(%esi),%esi + '\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 + '\x27', '\x00', '\x00', + '\x00', '\x00' }; + const char nop12[12] = { '\x8d', '\xb6', '\x00', // leal 0L(%esi),%esi + '\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 + '\x8d', '\xbc', '\x27', + '\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', '\x8d', '\xbc', + '\x27', '\x00', '\x00', + '\x00', '\x00' }; + const char nop15[15] = { '\xeb', '\x0d', '\x90', // jmp .+15 + '\x90', '\x90', '\x90', // nop,nop,nop,... + '\x90', '\x90', '\x90', + '\x90', '\x90', '\x90', + '\x90', '\x90', '\x90' }; + + const char* nops[16] = { + NULL, + nop1, nop2, nop3, nop4, nop5, nop6, nop7, + nop8, nop9, nop10, nop11, nop12, nop13, nop14, nop15 + }; + + return std::string(nops[length], length); +} + +// Return the value to use for the base of a DW_EH_PE_datarel offset +// in an FDE. Solaris and SVR4 use DW_EH_PE_datarel because their +// assembler can not write out the difference between two labels in +// different sections, so instead of using a pc-relative value they +// use an offset from the GOT. + +uint64_t +Target_i386::do_ehframe_datarel_base() const +{ + gold_assert(this->global_offset_table_ != NULL); + Symbol* sym = this->global_offset_table_; + Sized_symbol<32>* ssym = static_cast*>(sym); + return ssym->value(); +} + +// Return whether SYM should be treated as a call to a non-split +// function. We don't want that to be true of a call to a +// get_pc_thunk function. + +bool +Target_i386::do_is_call_to_non_split(const Symbol* sym, unsigned int) const +{ + return (sym->type() == elfcpp::STT_FUNC + && !is_prefix_of("__i686.get_pc_thunk.", sym->name())); +} + +// FNOFFSET in section SHNDX in OBJECT is the start of a function +// compiled with -fsplit-stack. The function calls non-split-stack +// code. We have to change the function so that it always ensures +// that it has enough stack space to run some random function. + +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 +{ + // The function starts with a comparison of the stack pointer and a + // field in the TCB. This is followed by a jump. + + // cmp %gs:NN,%esp + if (this->match_view(view, view_size, fnoffset, "\x65\x3b\x25", 3) + && fnsize > 7) + { + // We will call __morestack if the carry flag is set after this + // comparison. We turn the comparison into an stc instruction + // and some nops. + view[fnoffset] = '\xf9'; + this->set_view_to_nop(view, view_size, fnoffset + 1, 6); + } + // lea NN(%esp),%ecx + // lea NN(%esp),%edx + else if ((this->match_view(view, view_size, fnoffset, "\x8d\x8c\x24", 3) + || this->match_view(view, view_size, fnoffset, "\x8d\x94\x24", 3)) + && fnsize > 7) + { + // This is loading an offset from the stack pointer for a + // comparison. The offset is negative, so we decrease the + // offset by the amount of space we need for the stack. This + // means we will avoid calling __morestack if there happens to + // be plenty of space on the stack already. + unsigned char* pval = view + fnoffset + 3; + uint32_t val = elfcpp::Swap_unaligned<32, false>::readval(pval); + val -= parameters->options().split_stack_adjust_size(); + elfcpp::Swap_unaligned<32, false>::writeval(pval, val); + } + else + { + if (!object->has_no_split_stack()) + object->error(_("failed to match split-stack sequence at " + "section %u offset %0zx"), + shndx, static_cast(fnoffset)); + return; + } + + // We have to change the function so that it calls + // __morestack_non_split instead of __morestack. The former will + // allocate additional stack space. + *from = "__morestack"; + *to = "__morestack_non_split"; +} + +// 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 +{ +public: + Target_selector_i386() + : Target_selector_freebsd(elfcpp::EM_386, 32, false, + "elf32-i386", "elf32-i386-freebsd", + "elf_i386") + { } + + Target* + do_instantiate_target() + { return new Target_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); + } + + virtual std::string + do_code_fill(section_size_type length) const; + + 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 + "_start" // entry_symbol_name +}; + +#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 +}; + +// Return a string used to fill a code section with nops. +// For NaCl, long NOPs are only valid if they do not cross +// bundle alignment boundaries, so keep it simple with one-byte NOPs. +std::string +Target_i386_nacl::do_code_fill(section_size_type length) const +{ + return std::string(length, static_cast(0x90)); +} + +// The selector for i386-nacl object files. + +class Target_selector_i386_nacl + : public Target_selector_nacl +{ + public: + Target_selector_i386_nacl() + : Target_selector_nacl("x86-32", + "elf32-i386-nacl", + "elf_i386_nacl") + { } +}; + +Target_selector_i386_nacl target_selector_i386; + +} // End anonymous namespace. diff --git a/binutils-2.25/gold/icf.cc b/binutils-2.25/gold/icf.cc new file mode 100644 index 00000000..a58e34f3 --- /dev/null +++ b/binutils-2.25/gold/icf.cc @@ -0,0 +1,849 @@ +// icf.cc -- Identical Code Folding. +// +// Copyright 2009, 2010, 2011 Free Software Foundation, Inc. +// Written by Sriraman Tallam . + +// 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. + +// Identical Code Folding Algorithm +// ---------------------------------- +// Detecting identical functions is done here and the basic algorithm +// is as follows. A checksum is computed on each foldable section using +// its contents and relocations. If the symbol name corresponding to +// a relocation is known it is used to compute the checksum. If the +// symbol name is not known the stringified name of the object and the +// section number pointed to by the relocation is used. The checksums +// are stored as keys in a hash map and a section is identical to some +// other section if its checksum is already present in the hash map. +// Checksum collisions are handled by using a multimap and explicitly +// checking the contents when two sections have the same checksum. +// +// However, two functions A and B with identical text but with +// relocations pointing to different foldable sections can be identical if +// the corresponding foldable sections to which their relocations point to +// turn out to be identical. Hence, this checksumming process must be +// done repeatedly until convergence is obtained. Here is an example for +// the following case : +// +// int funcA () int funcB () +// { { +// return foo(); return goo(); +// } } +// +// The functions funcA and funcB are identical if functions foo() and +// goo() are identical. +// +// Hence, as described above, we repeatedly do the checksumming, +// assigning identical functions to the same group, until convergence is +// obtained. Now, we have two different ways to do this depending on how +// we initialize. +// +// Algorithm I : +// ----------- +// We can start with marking all functions as different and repeatedly do +// the checksumming. This has the advantage that we do not need to wait +// for convergence. We can stop at any point and correctness will be +// guaranteed although not all cases would have been found. However, this +// has a problem that some cases can never be found even if it is run until +// convergence. Here is an example with mutually recursive functions : +// +// int funcA (int a) int funcB (int a) +// { { +// if (a == 1) if (a == 1) +// return 1; return 1; +// return 1 + funcB(a - 1); return 1 + funcA(a - 1); +// } } +// +// In this example funcA and funcB are identical and one of them could be +// folded into the other. However, if we start with assuming that funcA +// and funcB are not identical, the algorithm, even after it is run to +// convergence, cannot detect that they are identical. It should be noted +// that even if the functions were self-recursive, Algorithm I cannot catch +// that they are identical, at least as is. +// +// Algorithm II : +// ------------ +// Here we start with marking all functions as identical and then repeat +// the checksumming until convergence. This can detect the above case +// mentioned above. It can detect all cases that Algorithm I can and more. +// However, the caveat is that it has to be run to convergence. It cannot +// be stopped arbitrarily like Algorithm I as correctness cannot be +// guaranteed. Algorithm II is not implemented. +// +// Algorithm I is used because experiments show that about three +// iterations are more than enough to achieve convergence. Algorithm I can +// handle recursive calls if it is changed to use a special common symbol +// for recursive relocs. This seems to be the most common case that +// Algorithm I could not catch as is. Mutually recursive calls are not +// frequent and Algorithm I wins because of its ability to be stopped +// arbitrarily. +// +// Caveat with using function pointers : +// ------------------------------------ +// +// Programs using function pointer comparisons/checks should use function +// folding with caution as the result of such comparisons could be different +// when folding takes place. This could lead to unexpected run-time +// behaviour. +// +// Safe Folding : +// ------------ +// +// ICF in safe mode folds only ctors and dtors if their function pointers can +// never be taken. Also, for X86-64, safe folding uses the relocation +// type to determine if a function's pointer is taken or not and only folds +// functions whose pointers are definitely not taken. +// +// Caveat with safe folding : +// ------------------------ +// +// This applies only to x86_64. +// +// Position independent executables are created from PIC objects (compiled +// with -fPIC) and/or PIE objects (compiled with -fPIE). For PIE objects, the +// relocation types for function pointer taken and a call are the same. +// Now, it is not always possible to tell if an object used in the link of +// a pie executable is a PIC object or a PIE object. Hence, for pie +// executables, using relocation types to disambiguate function pointers is +// currently disabled. +// +// Further, it is not correct to use safe folding to build non-pie +// executables using PIC/PIE objects. PIC/PIE objects have different +// relocation types for function pointers than non-PIC objects, and the +// current implementation of safe folding does not handle those relocation +// types. Hence, if used, functions whose pointers are taken could still be +// folded causing unpredictable run-time behaviour if the pointers were used +// in comparisons. +// +// +// +// How to run : --icf=[safe|all|none] +// Optional parameters : --icf-iterations --print-icf-sections +// +// Performance : Less than 20 % link-time overhead on industry strength +// applications. Up to 6 % text size reductions. + +#include "gold.h" +#include "object.h" +#include "gc.h" +#include "icf.h" +#include "symtab.h" +#include "libiberty.h" +#include "demangle.h" +#include "elfcpp.h" +#include "int_encoding.h" + +namespace gold +{ + +// This function determines if a section or a group of identical +// sections has unique contents. Such unique sections or groups can be +// declared final and need not be processed any further. +// Parameters : +// ID_SECTION : Vector mapping a section index to a Section_id pair. +// IS_SECN_OR_GROUP_UNIQUE : To check if a section or a group of identical +// sections is already known to be unique. +// SECTION_CONTENTS : Contains the section's text and relocs to sections +// that cannot be folded. SECTION_CONTENTS are NULL +// implies that this function is being called for the +// first time before the first iteration of icf. + +static void +preprocess_for_unique_sections(const std::vector& id_section, + std::vector* is_secn_or_group_unique, + std::vector* section_contents) +{ + Unordered_map uniq_map; + std::pair::iterator, bool> + uniq_map_insert; + + for (unsigned int i = 0; i < id_section.size(); i++) + { + if ((*is_secn_or_group_unique)[i]) + continue; + + uint32_t cksum; + Section_id secn = id_section[i]; + section_size_type plen; + if (section_contents == NULL) + { + // Lock the object so we can read from it. This is only called + // single-threaded from queue_middle_tasks, so it is OK to lock. + // Unfortunately we have no way to pass in a Task token. + const Task* dummy_task = reinterpret_cast(-1); + Task_lock_obj tl(dummy_task, secn.first); + const unsigned char* contents; + contents = secn.first->section_contents(secn.second, + &plen, + false); + cksum = xcrc32(contents, plen, 0xffffffff); + } + else + { + const unsigned char* contents_array = reinterpret_cast + ((*section_contents)[i].c_str()); + cksum = xcrc32(contents_array, (*section_contents)[i].length(), + 0xffffffff); + } + uniq_map_insert = uniq_map.insert(std::make_pair(cksum, i)); + if (uniq_map_insert.second) + { + (*is_secn_or_group_unique)[i] = true; + } + else + { + (*is_secn_or_group_unique)[i] = false; + (*is_secn_or_group_unique)[uniq_map_insert.first->second] = false; + } + } +} + +// This returns the buffer containing the section's contents, both +// text and relocs. Relocs are differentiated as those pointing to +// sections that could be folded and those that cannot. Only relocs +// pointing to sections that could be folded are recomputed on +// subsequent invocations of this function. +// Parameters : +// FIRST_ITERATION : true if it is the first invocation. +// SECN : Section for which contents are desired. +// SECTION_NUM : Unique section number of this section. +// NUM_TRACKED_RELOCS : Vector reference to store the number of relocs +// to ICF sections. +// KEPT_SECTION_ID : Vector which maps folded sections to kept sections. +// SECTION_CONTENTS : Store the section's text and relocs to non-ICF +// sections. + +static std::string +get_section_contents(bool first_iteration, + const Section_id& secn, + unsigned int section_num, + unsigned int* num_tracked_relocs, + Symbol_table* symtab, + const std::vector& kept_section_id, + std::vector* section_contents) +{ + // Lock the object so we can read from it. This is only called + // single-threaded from queue_middle_tasks, so it is OK to lock. + // Unfortunately we have no way to pass in a Task token. + const Task* dummy_task = reinterpret_cast(-1); + Task_lock_obj tl(dummy_task, secn.first); + + section_size_type plen; + const unsigned char* contents = NULL; + if (first_iteration) + contents = secn.first->section_contents(secn.second, &plen, false); + + // The buffer to hold all the contents including relocs. A checksum + // is then computed on this buffer. + std::string buffer; + std::string icf_reloc_buffer; + + if (num_tracked_relocs) + *num_tracked_relocs = 0; + + Icf::Reloc_info_list& reloc_info_list = + symtab->icf()->reloc_info_list(); + + Icf::Reloc_info_list::iterator it_reloc_info_list = + reloc_info_list.find(secn); + + buffer.clear(); + icf_reloc_buffer.clear(); + + // Process relocs and put them into the buffer. + + if (it_reloc_info_list != reloc_info_list.end()) + { + Icf::Sections_reachable_info v = + (it_reloc_info_list->second).section_info; + // Stores the information of the symbol pointed to by the reloc. + Icf::Symbol_info s = (it_reloc_info_list->second).symbol_info; + // Stores the addend and the symbol value. + Icf::Addend_info a = (it_reloc_info_list->second).addend_info; + // Stores the offset of the reloc. + Icf::Offset_info o = (it_reloc_info_list->second).offset_info; + Icf::Reloc_addend_size_info reloc_addend_size_info = + (it_reloc_info_list->second).reloc_addend_size_info; + Icf::Sections_reachable_info::iterator it_v = v.begin(); + Icf::Symbol_info::iterator it_s = s.begin(); + Icf::Addend_info::iterator it_a = a.begin(); + Icf::Offset_info::iterator it_o = o.begin(); + Icf::Reloc_addend_size_info::iterator it_addend_size = + reloc_addend_size_info.begin(); + + for (; it_v != v.end(); ++it_v, ++it_s, ++it_a, ++it_o, ++it_addend_size) + { + if (first_iteration + && it_v->first != NULL) + { + Symbol_location loc; + loc.object = it_v->first; + loc.shndx = it_v->second; + loc.offset = convert_types(it_a->first + + it_a->second); + // Look through function descriptors + parameters->target().function_location(&loc); + if (loc.shndx != it_v->second) + { + it_v->second = loc.shndx; + // Modify symvalue/addend to the code entry. + it_a->first = loc.offset; + it_a->second = 0; + } + } + + // ADDEND_STR stores the symbol value and addend and offset, + // each at most 16 hex digits long. it_a points to a pair + // where first is the symbol value and second is the + // addend. + char addend_str[50]; + + // It would be nice if we could use format macros in inttypes.h + // here but there are not in ISO/IEC C++ 1998. + snprintf(addend_str, sizeof(addend_str), "%llx %llx %llux", + static_cast((*it_a).first), + static_cast((*it_a).second), + static_cast(*it_o)); + + // If the symbol pointed to by the reloc is not in an ordinary + // section or if the symbol type is not FROM_OBJECT, then the + // object is NULL. + if (it_v->first == NULL) + { + if (first_iteration) + { + // If the symbol name is available, use it. + if ((*it_s) != NULL) + buffer.append((*it_s)->name()); + // Append the addend. + buffer.append(addend_str); + buffer.append("@"); + } + continue; + } + + Section_id reloc_secn(it_v->first, it_v->second); + + // If this reloc turns back and points to the same section, + // like a recursive call, use a special symbol to mark this. + if (reloc_secn.first == secn.first + && reloc_secn.second == secn.second) + { + if (first_iteration) + { + buffer.append("R"); + buffer.append(addend_str); + buffer.append("@"); + } + continue; + } + Icf::Uniq_secn_id_map& section_id_map = + symtab->icf()->section_to_int_map(); + Icf::Uniq_secn_id_map::iterator section_id_map_it = + section_id_map.find(reloc_secn); + bool is_sym_preemptible = (*it_s != NULL + && !(*it_s)->is_from_dynobj() + && !(*it_s)->is_undefined() + && (*it_s)->is_preemptible()); + if (!is_sym_preemptible + && section_id_map_it != section_id_map.end()) + { + // This is a reloc to a section that might be folded. + if (num_tracked_relocs) + (*num_tracked_relocs)++; + + char kept_section_str[10]; + unsigned int secn_id = section_id_map_it->second; + snprintf(kept_section_str, sizeof(kept_section_str), "%u", + kept_section_id[secn_id]); + if (first_iteration) + { + buffer.append("ICF_R"); + buffer.append(addend_str); + } + icf_reloc_buffer.append(kept_section_str); + // Append the addend. + icf_reloc_buffer.append(addend_str); + icf_reloc_buffer.append("@"); + } + else + { + // This is a reloc to a section that cannot be folded. + // Process it only in the first iteration. + if (!first_iteration) + continue; + + uint64_t secn_flags = (it_v->first)->section_flags(it_v->second); + // This reloc points to a merge section. Hash the + // contents of this section. + if ((secn_flags & elfcpp::SHF_MERGE) != 0 + && parameters->target().can_icf_inline_merge_sections()) + { + uint64_t entsize = + (it_v->first)->section_entsize(it_v->second); + long long offset = it_a->first; + + unsigned long long addend = it_a->second; + // Ignoring the addend when it is a negative value. See the + // comments in Merged_symbol_value::Value in object.h. + if (addend < 0xffffff00) + offset = offset + addend; + + // For SHT_REL relocation sections, the addend is stored in the + // text section at the relocation offset. + uint64_t reloc_addend_value = 0; + const unsigned char* reloc_addend_ptr = + contents + static_cast(*it_o); + switch(*it_addend_size) + { + case 0: + { + break; + } + case 1: + { + reloc_addend_value = + read_from_pointer<8>(reloc_addend_ptr); + break; + } + case 2: + { + reloc_addend_value = + read_from_pointer<16>(reloc_addend_ptr); + break; + } + case 4: + { + reloc_addend_value = + read_from_pointer<32>(reloc_addend_ptr); + break; + } + case 8: + { + reloc_addend_value = + read_from_pointer<64>(reloc_addend_ptr); + break; + } + default: + gold_unreachable(); + } + offset = offset + reloc_addend_value; + + section_size_type secn_len; + const unsigned char* str_contents = + (it_v->first)->section_contents(it_v->second, + &secn_len, + false) + offset; + if ((secn_flags & elfcpp::SHF_STRINGS) != 0) + { + // String merge section. + const char* str_char = + reinterpret_cast(str_contents); + switch(entsize) + { + case 1: + { + buffer.append(str_char); + break; + } + case 2: + { + const uint16_t* ptr_16 = + reinterpret_cast(str_char); + unsigned int strlen_16 = 0; + // Find the NULL character. + while(*(ptr_16 + strlen_16) != 0) + strlen_16++; + buffer.append(str_char, strlen_16 * 2); + } + break; + case 4: + { + const uint32_t* ptr_32 = + reinterpret_cast(str_char); + unsigned int strlen_32 = 0; + // Find the NULL character. + while(*(ptr_32 + strlen_32) != 0) + strlen_32++; + buffer.append(str_char, strlen_32 * 4); + } + break; + default: + gold_unreachable(); + } + } + else + { + // Use the entsize to determine the length. + buffer.append(reinterpret_cast(str_contents), + entsize); + } + buffer.append("@"); + } + else if ((*it_s) != NULL) + { + // If symbol name is available use that. + buffer.append((*it_s)->name()); + // Append the addend. + buffer.append(addend_str); + buffer.append("@"); + } + else + { + // Symbol name is not available, like for a local symbol, + // use object and section id. + buffer.append(it_v->first->name()); + char secn_id[10]; + snprintf(secn_id, sizeof(secn_id), "%u",it_v->second); + buffer.append(secn_id); + // Append the addend. + buffer.append(addend_str); + buffer.append("@"); + } + } + } + } + + if (first_iteration) + { + buffer.append("Contents = "); + buffer.append(reinterpret_cast(contents), plen); + // Store the section contents that dont change to avoid recomputing + // during the next call to this function. + (*section_contents)[section_num] = buffer; + } + else + { + gold_assert(buffer.empty()); + // Reuse the contents computed in the previous iteration. + buffer.append((*section_contents)[section_num]); + } + + buffer.append(icf_reloc_buffer); + return buffer; +} + +// This function computes a checksum on each section to detect and form +// groups of identical sections. The first iteration does this for all +// sections. +// Further iterations do this only for the kept sections from each group to +// determine if larger groups of identical sections could be formed. The +// first section in each group is the kept section for that group. +// +// CRC32 is the checksumming algorithm and can have collisions. That is, +// two sections with different contents can have the same checksum. Hence, +// a multimap is used to maintain more than one group of checksum +// identical sections. A section is added to a group only after its +// contents are explicitly compared with the kept section of the group. +// +// Parameters : +// ITERATION_NUM : Invocation instance of this function. +// NUM_TRACKED_RELOCS : Vector reference to store the number of relocs +// to ICF sections. +// KEPT_SECTION_ID : Vector which maps folded sections to kept sections. +// ID_SECTION : Vector mapping a section to an unique integer. +// IS_SECN_OR_GROUP_UNIQUE : To check if a section or a group of identical +// sections is already known to be unique. +// SECTION_CONTENTS : Store the section's text and relocs to non-ICF +// sections. + +static bool +match_sections(unsigned int iteration_num, + Symbol_table* symtab, + std::vector* num_tracked_relocs, + std::vector* kept_section_id, + const std::vector& id_section, + std::vector* is_secn_or_group_unique, + std::vector* section_contents) +{ + Unordered_multimap section_cksum; + std::pair::iterator, + Unordered_multimap::iterator> key_range; + bool converged = true; + + if (iteration_num == 1) + preprocess_for_unique_sections(id_section, + is_secn_or_group_unique, + NULL); + else + preprocess_for_unique_sections(id_section, + is_secn_or_group_unique, + section_contents); + + std::vector full_section_contents; + + for (unsigned int i = 0; i < id_section.size(); i++) + { + full_section_contents.push_back(""); + if ((*is_secn_or_group_unique)[i]) + continue; + + Section_id secn = id_section[i]; + std::string this_secn_contents; + uint32_t cksum; + if (iteration_num == 1) + { + unsigned int num_relocs = 0; + this_secn_contents = get_section_contents(true, secn, i, &num_relocs, + symtab, (*kept_section_id), + section_contents); + (*num_tracked_relocs)[i] = num_relocs; + } + else + { + if ((*kept_section_id)[i] != i) + { + // This section is already folded into something. See + // if it should point to a different kept section. + unsigned int kept_section = (*kept_section_id)[i]; + if (kept_section != (*kept_section_id)[kept_section]) + { + (*kept_section_id)[i] = (*kept_section_id)[kept_section]; + } + continue; + } + this_secn_contents = get_section_contents(false, secn, i, NULL, + symtab, (*kept_section_id), + section_contents); + } + + const unsigned char* this_secn_contents_array = + reinterpret_cast(this_secn_contents.c_str()); + cksum = xcrc32(this_secn_contents_array, this_secn_contents.length(), + 0xffffffff); + size_t count = section_cksum.count(cksum); + + if (count == 0) + { + // Start a group with this cksum. + section_cksum.insert(std::make_pair(cksum, i)); + full_section_contents[i] = this_secn_contents; + } + else + { + key_range = section_cksum.equal_range(cksum); + Unordered_multimap::iterator it; + // Search all the groups with this cksum for a match. + for (it = key_range.first; it != key_range.second; ++it) + { + unsigned int kept_section = it->second; + if (full_section_contents[kept_section].length() + != this_secn_contents.length()) + continue; + if (memcmp(full_section_contents[kept_section].c_str(), + this_secn_contents.c_str(), + this_secn_contents.length()) != 0) + continue; + (*kept_section_id)[i] = kept_section; + converged = false; + break; + } + if (it == key_range.second) + { + // Create a new group for this cksum. + section_cksum.insert(std::make_pair(cksum, i)); + full_section_contents[i] = this_secn_contents; + } + } + // If there are no relocs to foldable sections do not process + // this section any further. + if (iteration_num == 1 && (*num_tracked_relocs)[i] == 0) + (*is_secn_or_group_unique)[i] = true; + } + + return converged; +} + +// During safe icf (--icf=safe), only fold functions that are ctors or dtors. +// This function returns true if the section name is that of a ctor or a dtor. + +static bool +is_function_ctor_or_dtor(const std::string& section_name) +{ + const char* mangled_func_name = strrchr(section_name.c_str(), '.'); + gold_assert(mangled_func_name != NULL); + if ((is_prefix_of("._ZN", mangled_func_name) + || is_prefix_of("._ZZ", mangled_func_name)) + && (is_gnu_v3_mangled_ctor(mangled_func_name + 1) + || is_gnu_v3_mangled_dtor(mangled_func_name + 1))) + { + return true; + } + return false; +} + +// This is the main ICF function called in gold.cc. This does the +// initialization and calls match_sections repeatedly (twice by default) +// which computes the crc checksums and detects identical functions. + +void +Icf::find_identical_sections(const Input_objects* input_objects, + Symbol_table* symtab) +{ + unsigned int section_num = 0; + std::vector num_tracked_relocs; + std::vector is_secn_or_group_unique; + std::vector section_contents; + const Target& target = parameters->target(); + + // Decide which sections are possible candidates first. + + for (Input_objects::Relobj_iterator p = input_objects->relobj_begin(); + p != input_objects->relobj_end(); + ++p) + { + // Lock the object so we can read from it. This is only called + // single-threaded from queue_middle_tasks, so it is OK to lock. + // Unfortunately we have no way to pass in a Task token. + const Task* dummy_task = reinterpret_cast(-1); + Task_lock_obj tl(dummy_task, *p); + + for (unsigned int i = 0;i < (*p)->shnum(); ++i) + { + const std::string section_name = (*p)->section_name(i); + if (!is_section_foldable_candidate(section_name)) + continue; + if (!(*p)->is_section_included(i)) + continue; + if (parameters->options().gc_sections() + && symtab->gc()->is_section_garbage(*p, i)) + continue; + // With --icf=safe, check if the mangled function name is a ctor + // or a dtor. The mangled function name can be obtained from the + // section name by stripping the section prefix. + if (parameters->options().icf_safe_folding() + && !is_function_ctor_or_dtor(section_name) + && (!target.can_check_for_function_pointers() + || section_has_function_pointers(*p, i))) + { + continue; + } + this->id_section_.push_back(Section_id(*p, i)); + this->section_id_[Section_id(*p, i)] = section_num; + this->kept_section_id_.push_back(section_num); + num_tracked_relocs.push_back(0); + is_secn_or_group_unique.push_back(false); + section_contents.push_back(""); + section_num++; + } + } + + unsigned int num_iterations = 0; + + // Default number of iterations to run ICF is 2. + unsigned int max_iterations = (parameters->options().icf_iterations() > 0) + ? parameters->options().icf_iterations() + : 2; + + bool converged = false; + + while (!converged && (num_iterations < max_iterations)) + { + num_iterations++; + converged = match_sections(num_iterations, symtab, + &num_tracked_relocs, &this->kept_section_id_, + this->id_section_, &is_secn_or_group_unique, + §ion_contents); + } + + if (parameters->options().print_icf_sections()) + { + if (converged) + gold_info(_("%s: ICF Converged after %u iteration(s)"), + program_name, num_iterations); + else + gold_info(_("%s: ICF stopped after %u iteration(s)"), + program_name, num_iterations); + } + + // Unfold --keep-unique symbols. + for (options::String_set::const_iterator p = + parameters->options().keep_unique_begin(); + p != parameters->options().keep_unique_end(); + ++p) + { + const char* name = p->c_str(); + Symbol* sym = symtab->lookup(name); + if (sym == NULL) + { + gold_warning(_("Could not find symbol %s to unfold\n"), name); + } + else if (sym->source() == Symbol::FROM_OBJECT + && !sym->object()->is_dynamic()) + { + Object* obj = sym->object(); + bool is_ordinary; + unsigned int shndx = sym->shndx(&is_ordinary); + if (is_ordinary) + { + this->unfold_section(obj, shndx); + } + } + + } + + this->icf_ready(); +} + +// Unfolds the section denoted by OBJ and SHNDX if folded. + +void +Icf::unfold_section(Object* obj, unsigned int shndx) +{ + Section_id secn(obj, shndx); + Uniq_secn_id_map::iterator it = this->section_id_.find(secn); + if (it == this->section_id_.end()) + return; + unsigned int section_num = it->second; + unsigned int kept_section_id = this->kept_section_id_[section_num]; + if (kept_section_id != section_num) + this->kept_section_id_[section_num] = section_num; +} + +// This function determines if the section corresponding to the +// given object and index is folded based on if the kept section +// is different from this section. + +bool +Icf::is_section_folded(Object* obj, unsigned int shndx) +{ + Section_id secn(obj, shndx); + Uniq_secn_id_map::iterator it = this->section_id_.find(secn); + if (it == this->section_id_.end()) + return false; + unsigned int section_num = it->second; + unsigned int kept_section_id = this->kept_section_id_[section_num]; + return kept_section_id != section_num; +} + +// This function returns the folded section for the given section. + +Section_id +Icf::get_folded_section(Object* dup_obj, unsigned int dup_shndx) +{ + Section_id dup_secn(dup_obj, dup_shndx); + Uniq_secn_id_map::iterator it = this->section_id_.find(dup_secn); + gold_assert(it != this->section_id_.end()); + unsigned int section_num = it->second; + unsigned int kept_section_id = this->kept_section_id_[section_num]; + Section_id folded_section = this->id_section_[kept_section_id]; + return folded_section; +} + +} // End of namespace gold. diff --git a/binutils-2.25/gold/icf.h b/binutils-2.25/gold/icf.h new file mode 100644 index 00000000..df6bc017 --- /dev/null +++ b/binutils-2.25/gold/icf.h @@ -0,0 +1,179 @@ +// icf.h -- Identical Code Folding + +// Copyright 2009, 2010, 2013 Free Software Foundation, Inc. +// Written by Sriraman Tallam . + +// 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. + +#ifndef GOLD_ICF_H +#define GOLD_ICF_H + +#include + +#include "elfcpp.h" +#include "symtab.h" +#include "object.h" + +namespace gold +{ + +class Object; +class Input_objects; +class Symbol_table; + +class Icf +{ + public: + typedef std::vector Sections_reachable_info; + typedef std::vector Symbol_info; + typedef std::vector > Addend_info; + typedef std::vector Offset_info; + typedef std::vector Reloc_addend_size_info; + typedef Unordered_map Uniq_secn_id_map; + typedef Unordered_set Secn_fptr_taken_set; + + typedef struct + { + // This stores the section corresponding to the reloc. + Sections_reachable_info section_info; + // This stores the symbol corresponding to the reloc. + Symbol_info symbol_info; + // This stores the symbol value and the addend for a reloc. + Addend_info addend_info; + Offset_info offset_info; + Reloc_addend_size_info reloc_addend_size_info; + } Reloc_info; + + typedef Unordered_map Reloc_info_list; + + Icf() + : id_section_(), section_id_(), kept_section_id_(), + fptr_section_id_(), + icf_ready_(false), + reloc_info_list_() + { } + + // Returns the kept folded identical section corresponding to + // dup_obj and dup_shndx. + Section_id + get_folded_section(Object* dup_obj, unsigned int dup_shndx); + + // Forms groups of identical sections where the first member + // of each group is the kept section during folding. + void + find_identical_sections(const Input_objects* input_objects, + Symbol_table* symtab); + + // This is set when ICF has been run and the groups of + // identical sections have been formed. + void + icf_ready() + { this->icf_ready_ = true; } + + // Returns true if ICF has been run. + bool + is_icf_ready() + { return this->icf_ready_; } + + // Unfolds the section denoted by OBJ and SHNDX if folded. + void + unfold_section(Object* obj, unsigned int shndx); + + // Returns the kept section corresponding to the + // given section. + bool + is_section_folded(Object* obj, unsigned int shndx); + + // Given an object and a section index, this returns true if the + // pointer of the function defined in this section is taken. + bool + section_has_function_pointers(Object* obj, unsigned int shndx) + { + return (this->fptr_section_id_.find(Section_id(obj, shndx)) + != this->fptr_section_id_.end()); + } + + // Records that a pointer of the function defined in this section + // is taken. + void + set_section_has_function_pointers(Object* obj, unsigned int shndx) + { + this->fptr_section_id_.insert(Section_id(obj, shndx)); + } + + // Checks if the section_name should be searched for relocs + // corresponding to taken function pointers. Ignores eh_frame + // and vtable sections. + inline bool + check_section_for_function_pointers(const std::string& section_name, + Target* target) + { + return (parameters->options().icf_safe_folding() + && target->can_check_for_function_pointers() + && target->section_may_have_icf_unsafe_pointers( + section_name.c_str())); + } + + // Returns a map of a section to info (Reloc_info) about its relocations. + Reloc_info_list& + reloc_info_list() + { return this->reloc_info_list_; } + + // Returns a mapping of each section to a unique integer. + Uniq_secn_id_map& + section_to_int_map() + { return this->section_id_; } + + private: + + // Maps integers to sections. + std::vector id_section_; + // Does the reverse. + Uniq_secn_id_map section_id_; + // Given a section id, this maps it to the id of the kept + // section. If the id's are the same then this section is + // not folded. + std::vector kept_section_id_; + // Given a section id, this says if the pointer to this + // function is taken in which case it is dangerous to fold + // this function. + Secn_fptr_taken_set fptr_section_id_; + // Flag to indicate if ICF has been run. + bool icf_ready_; + // This list is populated by gc_process_relocs in gc.h. + Reloc_info_list reloc_info_list_; +}; + +// This function returns true if this section corresponds to a function that +// should be considered by icf as a possible candidate for folding. Some +// earlier gcc versions, like 4.0.3, put constructors and destructors in +// .gnu.linkonce.t sections and hence should be included too. +inline bool +is_section_foldable_candidate(const std::string& section_name) +{ + const char* section_name_cstr = section_name.c_str(); + return (is_prefix_of(".text", section_name_cstr) + || is_prefix_of(".gnu.linkonce.t", section_name_cstr)); +} + +} // End of namespace gold. + +#endif diff --git a/binutils-2.25/gold/incremental-dump.cc b/binutils-2.25/gold/incremental-dump.cc new file mode 100644 index 00000000..53652655 --- /dev/null +++ b/binutils-2.25/gold/incremental-dump.cc @@ -0,0 +1,518 @@ +// incremental.cc -- incremental linking test/debug tool + +// Copyright 2009, 2010 Free Software Foundation, Inc. +// Written by Rafael Avila de Espindola + +// 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. + + +// This file is a (still incomplete) test/debug tool that should display +// all information available in the incremental linking sections in a +// format that is easy to read. +// Once the format is a bit more stable, this should probably be moved to +// readelf. Because of that, the use of gold's data structures and functions +// is just a short term convenience and not a design decision. + +#include "gold.h" + +#include +#include +#include + +#include "incremental.h" + +namespace gold +{ + class Output_file; +} + +using namespace gold; + +template +static typename Incremental_inputs_reader:: + Incremental_input_entry_reader +find_input_containing_global( + Incremental_inputs_reader& incremental_inputs, + unsigned int offset, + unsigned int* symndx) +{ + typedef Incremental_inputs_reader Inputs_reader; + static const unsigned int global_sym_entry_size = + Incremental_inputs_reader::global_sym_entry_size; + + for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i) + { + typename Inputs_reader::Incremental_input_entry_reader input_file = + incremental_inputs.input_file(i); + if (input_file.type() != INCREMENTAL_INPUT_OBJECT + && input_file.type() != INCREMENTAL_INPUT_ARCHIVE_MEMBER) + continue; + unsigned int nsyms = input_file.get_global_symbol_count(); + if (offset >= input_file.get_symbol_offset(0) + && offset < input_file.get_symbol_offset(nsyms)) + { + *symndx = ((offset - input_file.get_symbol_offset(0)) + / global_sym_entry_size); + return input_file; + } + } + gold_unreachable(); +} + +template +static void +dump_incremental_inputs(const char* argv0, const char* filename, + Sized_incremental_binary* inc) +{ + typedef Incremental_binary::Location Location; + typedef Incremental_binary::View View; + typedef Incremental_inputs_reader Inputs_reader; + typedef typename Inputs_reader::Incremental_input_entry_reader Entry_reader; + + if (!inc->has_incremental_info()) + { + fprintf(stderr, "%s: %s: no .gnu_incremental_inputs section\n", argv0, + filename); + exit(1); + } + + // Create a reader object for the .gnu_incremental_inputs section. + + Incremental_inputs_reader + incremental_inputs(inc->inputs_reader()); + + if (incremental_inputs.version() != 2) + { + fprintf(stderr, "%s: %s: unknown incremental version %d\n", argv0, + filename, incremental_inputs.version()); + exit(1); + } + + const char* command_line = incremental_inputs.command_line(); + if (command_line == NULL) + { + fprintf(stderr, + "%s: %s: failed to get link command line\n", + argv0, filename); + exit(1); + } + printf("Link command line: %s\n", command_line); + + printf("\nInput files:\n"); + for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i) + { + Entry_reader input_file = incremental_inputs.input_file(i); + + const char* objname = input_file.filename(); + if (objname == NULL) + { + fprintf(stderr,"%s: %s: failed to get file name for object %u\n", + argv0, filename, i); + exit(1); + } + printf("[%d] %s\n", i, objname); + + Timespec mtime = input_file.get_mtime(); + printf(" Timestamp: %llu.%09d %s", + static_cast(mtime.seconds), + mtime.nanoseconds, + ctime(&mtime.seconds)); + + printf(" Serial Number: %d\n", input_file.arg_serial()); + printf(" In System Directory: %s\n", + input_file.is_in_system_directory() ? "true" : "false"); + + Incremental_input_type input_type = input_file.type(); + printf(" Type: "); + switch (input_type) + { + case INCREMENTAL_INPUT_OBJECT: + case INCREMENTAL_INPUT_ARCHIVE_MEMBER: + printf("%s\n", (input_type == INCREMENTAL_INPUT_OBJECT + ? "Object" : "Archive member")); + printf(" Input section count: %d\n", + input_file.get_input_section_count()); + printf(" Global symbol count: %d\n", + input_file.get_global_symbol_count()); + printf(" Local symbol offset: %d\n", + input_file.get_local_symbol_offset()); + printf(" Local symbol count: %d\n", + input_file.get_local_symbol_count()); + printf(" First dynamic reloc: %d\n", + input_file.get_first_dyn_reloc()); + printf(" Dynamic reloc count: %d\n", + input_file.get_dyn_reloc_count()); + printf(" COMDAT group count: %d\n", + input_file.get_comdat_group_count()); + break; + case INCREMENTAL_INPUT_ARCHIVE: + printf("Archive\n"); + printf(" Member count: %d\n", input_file.get_member_count()); + printf(" Unused symbol count: %d\n", + input_file.get_unused_symbol_count()); + break; + case INCREMENTAL_INPUT_SHARED_LIBRARY: + printf("Shared library\n"); + printf(" As needed: %s\n", + input_file.as_needed() ? "true" : "false"); + printf(" soname: %s\n", + input_file.get_soname()); + printf(" Symbol count: %d\n", + input_file.get_global_symbol_count()); + break; + case INCREMENTAL_INPUT_SCRIPT: + printf("Linker script\n"); + printf(" Object count: %d\n", input_file.get_object_count()); + break; + default: + fprintf(stderr, "%s: invalid file type for object %u: %d\n", + argv0, i, input_type); + exit(1); + } + } + + printf("\nInput sections:\n"); + for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i) + { + Entry_reader input_file(incremental_inputs.input_file(i)); + + if (input_file.type() != INCREMENTAL_INPUT_OBJECT + && input_file.type() != INCREMENTAL_INPUT_ARCHIVE_MEMBER) + continue; + + const char* objname = input_file.filename(); + if (objname == NULL) + { + fprintf(stderr,"%s: %s: failed to get file name for object %u\n", + argv0, filename, i); + exit(1); + } + + printf("[%d] %s\n", i, objname); + + printf(" %3s %6s %8s %8s %s\n", + "n", "outndx", "offset", "size", "name"); + unsigned int nsections = input_file.get_input_section_count(); + for (unsigned int shndx = 0; shndx < nsections; ++shndx) + { + typename Entry_reader::Input_section_info info( + input_file.get_input_section(shndx)); + printf(" %3d %6d %8lld %8lld %s\n", shndx + 1, + info.output_shndx, + static_cast(info.sh_offset), + static_cast(info.sh_size), + info.name); + } + + unsigned int ncomdat = input_file.get_comdat_group_count(); + for (unsigned int i = 0; i < ncomdat; ++i) + printf(" Comdat group: %s\n", + input_file.get_comdat_group_signature(i)); + } + + // Get a view of the .symtab section. + + elfcpp::Elf_file elf_file(inc); + + unsigned int symtab_shndx = elf_file.find_section_by_type(elfcpp::SHT_SYMTAB); + if (symtab_shndx == elfcpp::SHN_UNDEF) // Not found. + { + fprintf(stderr, "%s: %s: no symbol table section\n", argv0, filename); + exit(1); + } + Location symtab_location(elf_file.section_contents(symtab_shndx)); + View symtab_view(inc->view(symtab_location)); + + // Get a view of the .strtab section. + + unsigned int strtab_shndx = elf_file.section_link(symtab_shndx); + if (strtab_shndx == elfcpp::SHN_UNDEF + || strtab_shndx > elf_file.shnum() + || elf_file.section_type(strtab_shndx) != elfcpp::SHT_STRTAB) + { + fprintf(stderr, "%s: %s: no string table section\n", argv0, filename); + exit(1); + } + Location strtab_location(elf_file.section_contents(strtab_shndx)); + View strtab_view(inc->view(strtab_location)); + elfcpp::Elf_strtab strtab(strtab_view.data(), strtab_location.data_size); + + // The .gnu_incremental_symtab section contains entries that parallel + // the global symbols of the main symbol table. The sh_info field + // of the main symbol table's section header tells us how many global + // symbols there are, but that count does not include any global + // symbols that were forced local during the link. Therefore, we + // use the size of the .gnu_incremental_symtab section to deduce + // the number of global symbols + forced-local symbols there are + // in the symbol table. + Incremental_symtab_reader isymtab(inc->symtab_reader()); + Incremental_relocs_reader irelocs(inc->relocs_reader()); + unsigned int sym_size = elfcpp::Elf_sizes::sym_size; + unsigned int nsyms = symtab_location.data_size / sym_size; + unsigned int nglobals = isymtab.symbol_count(); + unsigned int first_global = nsyms - nglobals; + unsigned const char* sym_p; + + printf("\nGlobal symbols per input file:\n"); + for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i) + { + Entry_reader input_file(incremental_inputs.input_file(i)); + + if (input_file.type() != INCREMENTAL_INPUT_OBJECT + && input_file.type() != INCREMENTAL_INPUT_ARCHIVE_MEMBER + && input_file.type() != INCREMENTAL_INPUT_SHARED_LIBRARY) + continue; + + const char* objname = input_file.filename(); + if (objname == NULL) + { + fprintf(stderr,"%s: %s: failed to get file name for object %u\n", + argv0, filename, i); + exit(1); + } + + printf("[%d] %s\n", i, objname); + + unsigned int nsyms = input_file.get_global_symbol_count(); + if (nsyms > 0) + printf(" %6s %6s %8s %8s %8s %8s\n", + "outndx", "shndx", "offset", "chain", "#relocs", "rbase"); + if (input_file.type() == INCREMENTAL_INPUT_SHARED_LIBRARY) + { + for (unsigned int symndx = 0; symndx < nsyms; ++symndx) + { + bool is_def; + bool is_copy; + unsigned int output_symndx = + input_file.get_output_symbol_index(symndx, &is_def, &is_copy); + sym_p = symtab_view.data() + output_symndx * sym_size; + elfcpp::Sym sym(sym_p); + const char* symname; + if (!strtab.get_c_string(sym.get_st_name(), &symname)) + symname = ""; + printf(" %6d %6s %8s %8s %8s %8s %-5s %s\n", + output_symndx, + "", "", "", "", "", + is_copy ? "COPY" : (is_def ? "DEF" : "UNDEF"), + symname); + } + } + else + { + for (unsigned int symndx = 0; symndx < nsyms; ++symndx) + { + Incremental_global_symbol_reader info( + input_file.get_global_symbol_reader(symndx)); + unsigned int output_symndx = info.output_symndx(); + sym_p = symtab_view.data() + output_symndx * sym_size; + elfcpp::Sym sym(sym_p); + const char* symname; + if (!strtab.get_c_string(sym.get_st_name(), &symname)) + symname = ""; + printf(" %6d %6d %8d %8d %8d %8d %-5s %s\n", + output_symndx, + info.shndx() == -1U ? -1 : info.shndx(), + input_file.get_symbol_offset(symndx), + info.next_offset(), + info.reloc_count(), + info.reloc_offset(), + (info.shndx() == -1U + ? "BASE" + : info.shndx() == 0 ? "UNDEF" : "DEF"), + symname); + } + } + } + + sym_p = symtab_view.data() + first_global * sym_size; + printf("\nGlobal symbol table:\n"); + for (unsigned int i = 0; i < nglobals; i++) + { + elfcpp::Sym sym(sym_p); + const char* symname; + if (!strtab.get_c_string(sym.get_st_name(), &symname)) + symname = ""; + printf("[%d] %s\n", first_global + i, symname); + unsigned int offset = isymtab.get_list_head(i); + while (offset > 0) + { + unsigned int sym_ndx; + Entry_reader input_file = + find_input_containing_global(incremental_inputs, + offset, &sym_ndx); + Incremental_global_symbol_reader sym_info( + input_file.get_global_symbol_reader(sym_ndx)); + printf(" %s (first reloc: %d, reloc count: %d)", + input_file.filename(), sym_info.reloc_offset(), + sym_info.reloc_count()); + if (sym_info.output_symndx() != first_global + i) + printf(" ** wrong output symndx (%d) **", sym_info.output_symndx()); + printf("\n"); + // Dump the relocations from this input file for this symbol. + unsigned int r_off = sym_info.reloc_offset(); + for (unsigned int j = 0; j < sym_info.reloc_count(); j++) + { + printf(" %4d relocation type %3d shndx %2d" + " offset %016llx addend %016llx %s\n", + r_off, + irelocs.get_r_type(r_off), + irelocs.get_r_shndx(r_off), + static_cast(irelocs.get_r_offset(r_off)), + static_cast(irelocs.get_r_addend(r_off)), + symname); + r_off += irelocs.reloc_size; + } + offset = sym_info.next_offset(); + } + sym_p += sym_size; + } + + Incremental_got_plt_reader igot_plt(inc->got_plt_reader()); + unsigned int ngot = igot_plt.get_got_entry_count(); + unsigned int nplt = igot_plt.get_plt_entry_count(); + + printf("\nGOT entries:\n"); + for (unsigned int i = 0; i < ngot; ++i) + { + unsigned int got_type = igot_plt.get_got_type(i); + unsigned int got_symndx = igot_plt.get_got_symndx(i); + unsigned int got_input_index = igot_plt.get_got_input_index(i); + printf("[%d] type %02x, ", i, got_type & 0x7f); + if ((got_type & 0x7f) == 0x7f) + printf("reserved"); + else if (got_type & 0x80) + { + Entry_reader input_file = + incremental_inputs.input_file(got_input_index); + const char* objname = input_file.filename(); + printf("local: %s (%d)", objname, got_symndx); + } + else + { + sym_p = symtab_view.data() + got_symndx * sym_size; + elfcpp::Sym sym(sym_p); + const char* symname; + if (!strtab.get_c_string(sym.get_st_name(), &symname)) + symname = ""; + printf("global %s (%d)", symname, got_symndx); + } + printf("\n"); + } + + printf("\nPLT entries:\n"); + for (unsigned int i = 0; i < nplt; ++i) + { + unsigned int plt_desc = igot_plt.get_plt_desc(i); + printf("[%d] ", i); + sym_p = symtab_view.data() + plt_desc * sym_size; + elfcpp::Sym sym(sym_p); + const char* symname; + if (!strtab.get_c_string(sym.get_st_name(), &symname)) + symname = ""; + printf("%s (%d)\n", symname, plt_desc); + } + + printf("\nUnused archive symbols:\n"); + for (unsigned int i = 0; i < incremental_inputs.input_file_count(); ++i) + { + Entry_reader input_file(incremental_inputs.input_file(i)); + + if (input_file.type() != INCREMENTAL_INPUT_ARCHIVE) + continue; + + const char* objname = input_file.filename(); + if (objname == NULL) + { + fprintf(stderr,"%s: %s: failed to get file name for object %u\n", + argv0, filename, i); + exit(1); + } + + printf("[%d] %s\n", i, objname); + unsigned int nsyms = input_file.get_unused_symbol_count(); + for (unsigned int symndx = 0; symndx < nsyms; ++symndx) + printf(" %s\n", input_file.get_unused_symbol(symndx)); + } + +} + +int +main(int argc, char** argv) +{ + if (argc != 2) + { + fprintf(stderr, "Usage: %s \n", argv[0]); + return 1; + } + const char* filename = argv[1]; + + Output_file* file = new Output_file(filename); + + bool t = file->open_base_file(NULL, false); + if (!t) + { + fprintf(stderr, "%s: open_base_file(%s): %s\n", argv[0], filename, + strerror(errno)); + return 1; + } + + Incremental_binary* inc = open_incremental_binary(file); + + if (inc == NULL) + { + fprintf(stderr, "%s: open_incremental_binary(%s): %s\n", argv[0], + filename, strerror(errno)); + return 1; + } + + switch (parameters->size_and_endianness()) + { +#ifdef HAVE_TARGET_32_LITTLE + case Parameters::TARGET_32_LITTLE: + dump_incremental_inputs<32, false>( + argv[0], filename, + static_cast*>(inc)); + break; +#endif +#ifdef HAVE_TARGET_32_BIG + case Parameters::TARGET_32_BIG: + dump_incremental_inputs<32, true>( + argv[0], filename, + static_cast*>(inc)); + break; +#endif +#ifdef HAVE_TARGET_64_LITTLE + case Parameters::TARGET_64_LITTLE: + dump_incremental_inputs<64, false>( + argv[0], filename, + static_cast*>(inc)); + break; +#endif +#ifdef HAVE_TARGET_64_BIG + case Parameters::TARGET_64_BIG: + dump_incremental_inputs<64, true>( + argv[0], filename, + static_cast*>(inc)); + break; +#endif + default: + gold_unreachable(); + } + + return 0; +} diff --git a/binutils-2.25/gold/incremental.cc b/binutils-2.25/gold/incremental.cc new file mode 100644 index 00000000..714b1985 --- /dev/null +++ b/binutils-2.25/gold/incremental.cc @@ -0,0 +1,3123 @@ +// inremental.cc -- incremental linking support for gold + +// Copyright 2009, 2010, 2011, 2012 Free Software Foundation, Inc. +// Written by Mikolaj Zalewski . + +// 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 +#include +#include "libiberty.h" + +#include "elfcpp.h" +#include "options.h" +#include "output.h" +#include "symtab.h" +#include "incremental.h" +#include "archive.h" +#include "object.h" +#include "output.h" +#include "target-select.h" +#include "target.h" +#include "fileread.h" +#include "script.h" + +namespace gold { + +// Version number for the .gnu_incremental_inputs section. +// Version 1 was the initial checkin. +// Version 2 adds some padding to ensure 8-byte alignment where necessary. +const unsigned int INCREMENTAL_LINK_VERSION = 2; + +// This class manages the .gnu_incremental_inputs section, which holds +// the header information, a directory of input files, and separate +// entries for each input file. + +template +class Output_section_incremental_inputs : public Output_section_data +{ + public: + Output_section_incremental_inputs(const Incremental_inputs* inputs, + const Symbol_table* symtab) + : Output_section_data(size / 8), inputs_(inputs), symtab_(symtab) + { } + + protected: + // This is called to update the section size prior to assigning + // the address and file offset. + void + update_data_size() + { this->set_final_data_size(); } + + // Set the final data size. + void + set_final_data_size(); + + // Write the data to the file. + void + do_write(Output_file*); + + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _("** incremental_inputs")); } + + private: + // Write the section header. + unsigned char* + write_header(unsigned char* pov, unsigned int input_file_count, + section_offset_type command_line_offset); + + // Write the input file entries. + unsigned char* + write_input_files(unsigned char* oview, unsigned char* pov, + Stringpool* strtab); + + // Write the supplemental information blocks. + unsigned char* + write_info_blocks(unsigned char* oview, unsigned char* pov, + Stringpool* strtab, unsigned int* global_syms, + unsigned int global_sym_count); + + // Write the contents of the .gnu_incremental_symtab section. + void + write_symtab(unsigned char* pov, unsigned int* global_syms, + unsigned int global_sym_count); + + // Write the contents of the .gnu_incremental_got_plt section. + void + write_got_plt(unsigned char* pov, off_t view_size); + + // Typedefs for writing the data to the output sections. + typedef elfcpp::Swap Swap; + typedef elfcpp::Swap<16, big_endian> Swap16; + typedef elfcpp::Swap<32, big_endian> Swap32; + typedef elfcpp::Swap<64, big_endian> Swap64; + + // Sizes of various structures. + static const int sizeof_addr = size / 8; + static const int header_size = + Incremental_inputs_reader::header_size; + static const int input_entry_size = + Incremental_inputs_reader::input_entry_size; + static const unsigned int object_info_size = + Incremental_inputs_reader::object_info_size; + static const unsigned int input_section_entry_size = + Incremental_inputs_reader::input_section_entry_size; + static const unsigned int global_sym_entry_size = + Incremental_inputs_reader::global_sym_entry_size; + static const unsigned int incr_reloc_size = + Incremental_relocs_reader::reloc_size; + + // The Incremental_inputs object. + const Incremental_inputs* inputs_; + + // The symbol table. + const Symbol_table* symtab_; +}; + +// Inform the user why we don't do an incremental link. Not called in +// the obvious case of missing output file. TODO: Is this helpful? + +void +vexplain_no_incremental(const char* format, va_list args) +{ + char* buf = NULL; + if (vasprintf(&buf, format, args) < 0) + gold_nomem(); + gold_info(_("the link might take longer: " + "cannot perform incremental link: %s"), buf); + free(buf); +} + +void +explain_no_incremental(const char* format, ...) +{ + va_list args; + va_start(args, format); + vexplain_no_incremental(format, args); + va_end(args); +} + +// Report an error. + +void +Incremental_binary::error(const char* format, ...) const +{ + va_list args; + va_start(args, format); + // Current code only checks if the file can be used for incremental linking, + // so errors shouldn't fail the build, but only result in a fallback to a + // full build. + // TODO: when we implement incremental editing of the file, we may need a + // flag that will cause errors to be treated seriously. + vexplain_no_incremental(format, args); + va_end(args); +} + +// Return TRUE if a section of type SH_TYPE can be updated in place +// during an incremental update. We can update sections of type PROGBITS, +// NOBITS, INIT_ARRAY, FINI_ARRAY, PREINIT_ARRAY, and NOTE. All others +// will be regenerated. + +bool +can_incremental_update(unsigned int sh_type) +{ + return (sh_type == elfcpp::SHT_PROGBITS + || sh_type == elfcpp::SHT_NOBITS + || sh_type == elfcpp::SHT_INIT_ARRAY + || sh_type == elfcpp::SHT_FINI_ARRAY + || sh_type == elfcpp::SHT_PREINIT_ARRAY + || sh_type == elfcpp::SHT_NOTE); +} + +// Find the .gnu_incremental_inputs section and related sections. + +template +bool +Sized_incremental_binary::find_incremental_inputs_sections( + unsigned int* p_inputs_shndx, + unsigned int* p_symtab_shndx, + unsigned int* p_relocs_shndx, + unsigned int* p_got_plt_shndx, + unsigned int* p_strtab_shndx) +{ + unsigned int inputs_shndx = + this->elf_file_.find_section_by_type(elfcpp::SHT_GNU_INCREMENTAL_INPUTS); + if (inputs_shndx == elfcpp::SHN_UNDEF) // Not found. + return false; + + unsigned int symtab_shndx = + this->elf_file_.find_section_by_type(elfcpp::SHT_GNU_INCREMENTAL_SYMTAB); + if (symtab_shndx == elfcpp::SHN_UNDEF) // Not found. + return false; + if (this->elf_file_.section_link(symtab_shndx) != inputs_shndx) + return false; + + unsigned int relocs_shndx = + this->elf_file_.find_section_by_type(elfcpp::SHT_GNU_INCREMENTAL_RELOCS); + if (relocs_shndx == elfcpp::SHN_UNDEF) // Not found. + return false; + if (this->elf_file_.section_link(relocs_shndx) != inputs_shndx) + return false; + + unsigned int got_plt_shndx = + this->elf_file_.find_section_by_type(elfcpp::SHT_GNU_INCREMENTAL_GOT_PLT); + if (got_plt_shndx == elfcpp::SHN_UNDEF) // Not found. + return false; + if (this->elf_file_.section_link(got_plt_shndx) != inputs_shndx) + return false; + + unsigned int strtab_shndx = this->elf_file_.section_link(inputs_shndx); + if (strtab_shndx == elfcpp::SHN_UNDEF + || strtab_shndx > this->elf_file_.shnum() + || this->elf_file_.section_type(strtab_shndx) != elfcpp::SHT_STRTAB) + return false; + + if (p_inputs_shndx != NULL) + *p_inputs_shndx = inputs_shndx; + if (p_symtab_shndx != NULL) + *p_symtab_shndx = symtab_shndx; + if (p_relocs_shndx != NULL) + *p_relocs_shndx = relocs_shndx; + if (p_got_plt_shndx != NULL) + *p_got_plt_shndx = got_plt_shndx; + if (p_strtab_shndx != NULL) + *p_strtab_shndx = strtab_shndx; + return true; +} + +// Set up the readers into the incremental info sections. + +template +void +Sized_incremental_binary::setup_readers() +{ + unsigned int inputs_shndx; + unsigned int symtab_shndx; + unsigned int relocs_shndx; + unsigned int got_plt_shndx; + unsigned int strtab_shndx; + + if (!this->find_incremental_inputs_sections(&inputs_shndx, &symtab_shndx, + &relocs_shndx, &got_plt_shndx, + &strtab_shndx)) + return; + + Location inputs_location(this->elf_file_.section_contents(inputs_shndx)); + Location symtab_location(this->elf_file_.section_contents(symtab_shndx)); + Location relocs_location(this->elf_file_.section_contents(relocs_shndx)); + Location got_plt_location(this->elf_file_.section_contents(got_plt_shndx)); + Location strtab_location(this->elf_file_.section_contents(strtab_shndx)); + + View inputs_view = this->view(inputs_location); + View symtab_view = this->view(symtab_location); + View relocs_view = this->view(relocs_location); + View got_plt_view = this->view(got_plt_location); + View strtab_view = this->view(strtab_location); + + elfcpp::Elf_strtab strtab(strtab_view.data(), strtab_location.data_size); + + this->inputs_reader_ = + Incremental_inputs_reader(inputs_view.data(), strtab); + this->symtab_reader_ = + Incremental_symtab_reader(symtab_view.data(), + symtab_location.data_size); + this->relocs_reader_ = + Incremental_relocs_reader(relocs_view.data(), + relocs_location.data_size); + this->got_plt_reader_ = + Incremental_got_plt_reader(got_plt_view.data()); + + // Find the main symbol table. + unsigned int main_symtab_shndx = + this->elf_file_.find_section_by_type(elfcpp::SHT_SYMTAB); + gold_assert(main_symtab_shndx != elfcpp::SHN_UNDEF); + this->main_symtab_loc_ = this->elf_file_.section_contents(main_symtab_shndx); + + // Find the main symbol string table. + 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()); + 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 + // input file, and (b) to record maps of files added from archive + // libraries and scripts. + Incremental_inputs_reader& inputs = this->inputs_reader_; + unsigned int count = inputs.input_file_count(); + this->input_objects_.resize(count); + this->input_entry_readers_.reserve(count); + this->library_map_.resize(count); + this->script_map_.resize(count); + for (unsigned int i = 0; i < count; i++) + { + Input_entry_reader input_file = inputs.input_file(i); + this->input_entry_readers_.push_back(Sized_input_reader(input_file)); + switch (input_file.type()) + { + case INCREMENTAL_INPUT_OBJECT: + case INCREMENTAL_INPUT_ARCHIVE_MEMBER: + case INCREMENTAL_INPUT_SHARED_LIBRARY: + // No special treatment necessary. + break; + case INCREMENTAL_INPUT_ARCHIVE: + { + Incremental_library* lib = + 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(); + for (unsigned int j = 0; j < member_count; j++) + { + int member_offset = input_file.get_member_offset(j); + int member_index = inputs.input_file_index(member_offset); + this->library_map_[member_index] = lib; + } + } + break; + case INCREMENTAL_INPUT_SCRIPT: + { + Script_info* script = new Script_info(input_file.filename(), i); + this->script_map_[i] = script; + unsigned int object_count = input_file.get_object_count(); + for (unsigned int j = 0; j < object_count; j++) + { + int object_offset = input_file.get_object_offset(j); + int object_index = inputs.input_file_index(object_offset); + this->script_map_[object_index] = script; + } + } + break; + default: + gold_unreachable(); + } + } + + // Initialize the map of global symbols. + unsigned int nglobals = this->symtab_reader_.symbol_count(); + this->symbol_map_.resize(nglobals); + + this->has_incremental_info_ = true; +} + +// Walk the list of input files given on the command line, and build +// a direct map of file index to the corresponding input argument. + +void +check_input_args(std::vector& input_args_map, + Input_arguments::const_iterator begin, + Input_arguments::const_iterator end) +{ + for (Input_arguments::const_iterator p = begin; + p != end; + ++p) + { + if (p->is_group()) + { + const Input_file_group* group = p->group(); + check_input_args(input_args_map, group->begin(), group->end()); + } + else if (p->is_lib()) + { + const Input_file_lib* lib = p->lib(); + 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(arg_serial <= input_args_map.size()); + gold_assert(input_args_map[arg_serial - 1] == 0); + input_args_map[arg_serial - 1] = &*p; + } + } + } +} + +// Determine whether an incremental link based on the existing output file +// can be done. + +template +bool +Sized_incremental_binary::do_check_inputs( + const Command_line& cmdline, + Incremental_inputs* incremental_inputs) +{ + Incremental_inputs_reader& inputs = this->inputs_reader_; + + if (!this->has_incremental_info_) + { + explain_no_incremental(_("no incremental data from previous build")); + return false; + } + + if (inputs.version() != INCREMENTAL_LINK_VERSION) + { + explain_no_incremental(_("different version of incremental build data")); + return false; + } + + if (incremental_inputs->command_line() != inputs.command_line()) + { + gold_debug(DEBUG_INCREMENTAL, + "old command line: %s", + inputs.command_line()); + gold_debug(DEBUG_INCREMENTAL, + "new command line: %s", + incremental_inputs->command_line().c_str()); + explain_no_incremental(_("command line changed")); + return false; + } + + // Walk the list of input files given on the command line, and build + // a direct map of argument serial numbers to the corresponding input + // arguments. + this->input_args_map_.resize(cmdline.number_of_input_files()); + check_input_args(this->input_args_map_, cmdline.begin(), cmdline.end()); + + // Walk the list of input files to check for conditions that prevent + // an incremental update link. + unsigned int count = inputs.input_file_count(); + for (unsigned int i = 0; i < count; i++) + { + Input_entry_reader input_file = inputs.input_file(i); + switch (input_file.type()) + { + case INCREMENTAL_INPUT_OBJECT: + case INCREMENTAL_INPUT_ARCHIVE_MEMBER: + case INCREMENTAL_INPUT_SHARED_LIBRARY: + case INCREMENTAL_INPUT_ARCHIVE: + // No special treatment necessary. + break; + case INCREMENTAL_INPUT_SCRIPT: + if (this->do_file_has_changed(i)) + { + explain_no_incremental(_("%s: script file changed"), + input_file.filename()); + return false; + } + break; + default: + gold_unreachable(); + } + } + + return true; +} + +// Return TRUE if input file N has changed since the last incremental link. + +template +bool +Sized_incremental_binary::do_file_has_changed( + unsigned int n) const +{ + Input_entry_reader input_file = this->inputs_reader_.input_file(n); + Incremental_disposition disp = INCREMENTAL_CHECK; + + // For files named in scripts, find the file that was actually named + // on the command line, so that we can get the incremental disposition + // flag. + Script_info* script = this->get_script_info(n); + if (script != NULL) + n = script->input_file_index(); + + const Input_argument* input_argument = this->get_input_argument(n); + if (input_argument != NULL) + disp = input_argument->file().options().incremental_disposition(); + + // For files at the beginning of the command line (i.e., those added + // implicitly by gcc), check whether the --incremental-startup-unchanged + // option was used. + if (disp == INCREMENTAL_STARTUP) + disp = parameters->options().incremental_startup_disposition(); + + if (disp != INCREMENTAL_CHECK) + return disp == INCREMENTAL_CHANGED; + + const char* filename = input_file.filename(); + Timespec old_mtime = input_file.get_mtime(); + Timespec new_mtime; + if (!get_mtime(filename, &new_mtime)) + { + // If we can't open get the current modification time, assume it has + // changed. If the file doesn't exist, we'll issue an error when we + // try to open it later. + return true; + } + + if (new_mtime.seconds > old_mtime.seconds) + return true; + if (new_mtime.seconds == old_mtime.seconds + && new_mtime.nanoseconds > old_mtime.nanoseconds) + return true; + return false; +} + +// Initialize the layout of the output file based on the existing +// output file. + +template +void +Sized_incremental_binary::do_init_layout(Layout* layout) +{ + typedef elfcpp::Shdr Shdr; + const int shdr_size = elfcpp::Elf_sizes::shdr_size; + + // Get views of the section headers and the section string table. + const off_t shoff = this->elf_file_.shoff(); + const unsigned int shnum = this->elf_file_.shnum(); + const unsigned int shstrndx = this->elf_file_.shstrndx(); + Location shdrs_location(shoff, shnum * shdr_size); + Location shstrndx_location(this->elf_file_.section_contents(shstrndx)); + View shdrs_view = this->view(shdrs_location); + View shstrndx_view = this->view(shstrndx_location); + elfcpp::Elf_strtab shstrtab(shstrndx_view.data(), + shstrndx_location.data_size); + + layout->set_incremental_base(this); + + // Initialize the layout. + this->section_map_.resize(shnum); + const unsigned char* pshdr = shdrs_view.data() + shdr_size; + for (unsigned int i = 1; i < shnum; i++) + { + Shdr shdr(pshdr); + const char* name; + if (!shstrtab.get_c_string(shdr.get_sh_name(), &name)) + name = NULL; + gold_debug(DEBUG_INCREMENTAL, + "Output section: %2d %08lx %08lx %08lx %3d %s", + i, + static_cast(shdr.get_sh_addr()), + static_cast(shdr.get_sh_offset()), + static_cast(shdr.get_sh_size()), + shdr.get_sh_type(), name ? name : ""); + this->section_map_[i] = layout->init_fixed_output_section(name, shdr); + pshdr += shdr_size; + } +} + +// Mark regions of the input file that must be kept unchanged. + +template +void +Sized_incremental_binary::do_reserve_layout( + unsigned int input_file_index) +{ + const int sym_size = elfcpp::Elf_sizes::sym_size; + + Input_entry_reader input_file = + this->inputs_reader_.input_file(input_file_index); + + if (input_file.type() == INCREMENTAL_INPUT_SHARED_LIBRARY) + { + // Reserve the BSS space used for COPY relocations. + unsigned int nsyms = input_file.get_global_symbol_count(); + Incremental_binary::View symtab_view(NULL); + unsigned int symtab_count; + elfcpp::Elf_strtab strtab(NULL, 0); + this->get_symtab_view(&symtab_view, &symtab_count, &strtab); + for (unsigned int i = 0; i < nsyms; ++i) + { + bool is_def; + bool is_copy; + unsigned int output_symndx = + input_file.get_output_symbol_index(i, &is_def, &is_copy); + if (is_copy) + { + const unsigned char* sym_p = (symtab_view.data() + + output_symndx * sym_size); + elfcpp::Sym gsym(sym_p); + unsigned int shndx = gsym.get_st_shndx(); + if (shndx < 1 || shndx >= this->section_map_.size()) + continue; + Output_section* os = this->section_map_[shndx]; + off_t offset = gsym.get_st_value() - os->address(); + os->reserve(offset, gsym.get_st_size()); + gold_debug(DEBUG_INCREMENTAL, + "Reserve for COPY reloc: %s, off %d, size %d", + os->name(), + static_cast(offset), + static_cast(gsym.get_st_size())); + } + } + return; + } + + unsigned int shnum = input_file.get_input_section_count(); + for (unsigned int i = 0; i < shnum; i++) + { + typename Input_entry_reader::Input_section_info sect = + input_file.get_input_section(i); + if (sect.output_shndx == 0 || sect.sh_offset == -1) + continue; + Output_section* os = this->section_map_[sect.output_shndx]; + gold_assert(os != NULL); + os->reserve(sect.sh_offset, sect.sh_size); + } +} + +// Process the GOT and PLT entries from the existing output file. + +template +void +Sized_incremental_binary::do_process_got_plt( + Symbol_table* symtab, + Layout* layout) +{ + Incremental_got_plt_reader got_plt_reader(this->got_plt_reader()); + Sized_target* target = + parameters->sized_target(); + + // Get the number of symbols in the main symbol table and in the + // incremental symbol table. The difference between the two counts + // is the index of the first forced-local or global symbol in the + // main symbol table. + unsigned int symtab_count = + this->main_symtab_loc_.data_size / elfcpp::Elf_sizes::sym_size; + unsigned int isym_count = this->symtab_reader_.symbol_count(); + unsigned int first_global = symtab_count - isym_count; + + // Tell the target how big the GOT and PLT sections are. + unsigned int got_count = got_plt_reader.get_got_entry_count(); + unsigned int plt_count = got_plt_reader.get_plt_entry_count(); + Output_data_got_base* got = + target->init_got_plt_for_update(symtab, layout, got_count, plt_count); + + // Read the GOT entries from the base file and build the outgoing GOT. + for (unsigned int i = 0; i < got_count; ++i) + { + unsigned int got_type = got_plt_reader.get_got_type(i); + if ((got_type & 0x7f) == 0x7f) + { + // This is the second entry of a pair. + got->reserve_slot(i); + continue; + } + unsigned int symndx = got_plt_reader.get_got_symndx(i); + if (got_type & 0x80) + { + // This is an entry for a local symbol. Ignore this entry if + // the object file was replaced. + unsigned int input_index = got_plt_reader.get_got_input_index(i); + gold_debug(DEBUG_INCREMENTAL, + "GOT entry %d, type %02x: (local symbol)", + i, got_type & 0x7f); + Sized_relobj_incr* obj = + this->input_object(input_index); + if (obj != NULL) + target->reserve_local_got_entry(i, obj, symndx, got_type & 0x7f); + } + else + { + // This is an entry for a global symbol. GOT_DESC is the symbol + // table index. + // FIXME: This should really be a fatal error (corrupt input). + gold_assert(symndx >= first_global && symndx < symtab_count); + Symbol* sym = this->global_symbol(symndx - first_global); + // Add the GOT entry only if the symbol is still referenced. + if (sym != NULL && sym->in_reg()) + { + gold_debug(DEBUG_INCREMENTAL, + "GOT entry %d, type %02x: %s", + i, got_type, sym->name()); + target->reserve_global_got_entry(i, sym, got_type); + } + } + } + + // Read the PLT entries from the base file and pass each to the target. + for (unsigned int i = 0; i < plt_count; ++i) + { + unsigned int plt_desc = got_plt_reader.get_plt_desc(i); + // FIXME: This should really be a fatal error (corrupt input). + gold_assert(plt_desc >= first_global && plt_desc < symtab_count); + Symbol* sym = this->global_symbol(plt_desc - first_global); + // Add the PLT entry only if the symbol is still referenced. + if (sym != NULL && sym->in_reg()) + { + gold_debug(DEBUG_INCREMENTAL, + "PLT entry %d: %s", + i, sym->name()); + target->register_global_plt_entry(symtab, layout, i, sym); + } + } +} + +// Emit COPY relocations from the existing output file. + +template +void +Sized_incremental_binary::do_emit_copy_relocs( + Symbol_table* symtab) +{ + Sized_target* target = + parameters->sized_target(); + + for (typename Copy_relocs::iterator p = this->copy_relocs_.begin(); + p != this->copy_relocs_.end(); + ++p) + { + if (!(*p).symbol->is_copied_from_dynobj()) + target->emit_copy_reloc(symtab, (*p).symbol, (*p).output_section, + (*p).offset); + } +} + +// Apply incremental relocations for symbols whose values have changed. + +template +void +Sized_incremental_binary::do_apply_incremental_relocs( + const Symbol_table* symtab, + Layout* layout, + Output_file* of) +{ + typedef typename elfcpp::Elf_types::Elf_Addr Address; + typedef typename elfcpp::Elf_types::Elf_Swxword Addend; + Incremental_symtab_reader isymtab(this->symtab_reader()); + Incremental_relocs_reader irelocs(this->relocs_reader()); + unsigned int nglobals = isymtab.symbol_count(); + const unsigned int incr_reloc_size = irelocs.reloc_size; + + Relocate_info relinfo; + relinfo.symtab = symtab; + relinfo.layout = layout; + relinfo.object = NULL; + relinfo.reloc_shndx = 0; + relinfo.reloc_shdr = NULL; + relinfo.data_shndx = 0; + relinfo.data_shdr = NULL; + + Sized_target* target = + parameters->sized_target(); + + for (unsigned int i = 0; i < nglobals; i++) + { + const Symbol* gsym = this->global_symbol(i); + + // If the symbol is not referenced from any unchanged input files, + // we do not need to reapply any of its relocations. + if (gsym == NULL) + continue; + + // If the symbol is defined in an unchanged file, we do not need to + // reapply any of its relocations. + if (gsym->source() == Symbol::FROM_OBJECT + && gsym->object()->is_incremental()) + continue; + + gold_debug(DEBUG_INCREMENTAL, + "Applying incremental relocations for global symbol %s [%d]", + gsym->name(), i); + + // Follow the linked list of input symbol table entries for this symbol. + // We don't bother to figure out whether the symbol table entry belongs + // to a changed or unchanged file because it's easier just to apply all + // the relocations -- although we might scribble over an area that has + // been reallocated, we do this before copying any new data into the + // output file. + unsigned int offset = isymtab.get_list_head(i); + while (offset > 0) + { + Incremental_global_symbol_reader sym_info = + this->inputs_reader().global_symbol_reader_at_offset(offset); + unsigned int r_base = sym_info.reloc_offset(); + unsigned int r_count = sym_info.reloc_count(); + + // Apply each relocation for this symbol table entry. + for (unsigned int j = 0; j < r_count; + ++j, r_base += incr_reloc_size) + { + unsigned int r_type = irelocs.get_r_type(r_base); + unsigned int r_shndx = irelocs.get_r_shndx(r_base); + Address r_offset = irelocs.get_r_offset(r_base); + Addend r_addend = irelocs.get_r_addend(r_base); + Output_section* os = this->output_section(r_shndx); + Address address = os->address(); + off_t section_offset = os->offset(); + size_t view_size = os->data_size(); + unsigned char* const view = of->get_output_view(section_offset, + view_size); + + gold_debug(DEBUG_INCREMENTAL, + " %08lx: %s + %d: type %d addend %ld", + (long)(section_offset + r_offset), + os->name(), + (int)r_offset, + r_type, + (long)r_addend); + + target->apply_relocation(&relinfo, r_offset, r_type, r_addend, + gsym, view, address, view_size); + + // FIXME: Do something more efficient if write_output_view + // ever becomes more than a no-op. + of->write_output_view(section_offset, view_size, view); + } + offset = sym_info.next_offset(); + } + } +} + +// Get a view of the main symbol table and the symbol string table. + +template +void +Sized_incremental_binary::get_symtab_view( + View* symtab_view, + unsigned int* nsyms, + elfcpp::Elf_strtab* strtab) +{ + *symtab_view = this->view(this->main_symtab_loc_); + *nsyms = this->main_symtab_loc_.data_size / elfcpp::Elf_sizes::sym_size; + + View strtab_view(this->view(this->main_strtab_loc_)); + *strtab = elfcpp::Elf_strtab(strtab_view.data(), + this->main_strtab_loc_.data_size); +} + +namespace +{ + +// Create a Sized_incremental_binary object of the specified size and +// endianness. Fails if the target architecture is not supported. + +template +Incremental_binary* +make_sized_incremental_binary(Output_file* file, + const elfcpp::Ehdr& ehdr) +{ + 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()); + return NULL; + } + + if (!parameters->target_valid()) + set_parameters_target(target); + else if (target != ¶meters->target()) + gold_error(_("%s: incompatible target"), file->filename()); + + return new Sized_incremental_binary(file, ehdr, target); +} + +} // End of anonymous namespace. + +// Create an Incremental_binary object for FILE. Returns NULL is this is not +// possible, e.g. FILE is not an ELF file or has an unsupported target. FILE +// should be opened. + +Incremental_binary* +open_incremental_binary(Output_file* file) +{ + off_t filesize = file->filesize(); + int want = elfcpp::Elf_recognizer::max_header_size; + if (filesize < want) + want = filesize; + + const unsigned char* p = file->get_input_view(0, want); + if (!elfcpp::Elf_recognizer::is_elf_file(p, want)) + { + explain_no_incremental(_("output is not an ELF file.")); + return NULL; + } + + int size = 0; + bool big_endian = false; + std::string error; + if (!elfcpp::Elf_recognizer::is_valid_header(p, want, &size, &big_endian, + &error)) + { + explain_no_incremental(error.c_str()); + return NULL; + } + + Incremental_binary* result = NULL; + if (size == 32) + { + if (big_endian) + { +#ifdef HAVE_TARGET_32_BIG + result = make_sized_incremental_binary<32, true>( + file, elfcpp::Ehdr<32, true>(p)); +#else + 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)); +#else + 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)); +#else + 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)); +#else + explain_no_incremental(_("unsupported file: 64-bit, little-endian")); +#endif + } + } + else + gold_unreachable(); + + return result; +} + +// Class Incremental_inputs. + +// Add the command line to the string table, setting +// command_line_key_. In incremental builds, the command line is +// stored in .gnu_incremental_inputs so that the next linker run can +// check if the command line options didn't change. + +void +Incremental_inputs::report_command_line(int argc, const char* const* argv) +{ + // Always store 'gold' as argv[0] to avoid a full relink if the user used a + // different path to the linker. + std::string args("gold"); + // Copied from collect_argv in main.cc. + for (int i = 1; i < argc; ++i) + { + // Adding/removing these options should not result in a full relink. + if (strcmp(argv[i], "--incremental") == 0 + || strcmp(argv[i], "--incremental-full") == 0 + || strcmp(argv[i], "--incremental-update") == 0 + || strcmp(argv[i], "--incremental-changed") == 0 + || strcmp(argv[i], "--incremental-unchanged") == 0 + || strcmp(argv[i], "--incremental-unknown") == 0 + || strcmp(argv[i], "--incremental-startup-unchanged") == 0 + || is_prefix_of("--incremental-base=", argv[i]) + || is_prefix_of("--incremental-patch=", argv[i]) + || is_prefix_of("--debug=", argv[i])) + continue; + if (strcmp(argv[i], "--incremental-base") == 0 + || strcmp(argv[i], "--incremental-patch") == 0 + || strcmp(argv[i], "--debug") == 0) + { + // When these options are used without the '=', skip the + // following parameter as well. + ++i; + continue; + } + + args.append(" '"); + // 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; + } + args.append("'"); + } + + this->command_line_ = args; + this->strtab_->add(this->command_line_.c_str(), false, + &this->command_line_key_); +} + +// Record the input archive file ARCHIVE. This is called by the +// Add_archive_symbols task before determining which archive members +// to include. We create the Incremental_archive_entry here and +// attach it to the Archive, but we do not add it to the list of +// input objects until report_archive_end is called. + +void +Incremental_inputs::report_archive_begin(Library_base* arch, + unsigned int arg_serial, + Script_info* script_info) +{ + Stringpool::Key filename_key; + Timespec mtime = arch->get_mtime(); + + // For a file loaded from a script, don't record its argument serial number. + if (script_info != NULL) + arg_serial = 0; + + this->strtab_->add(arch->filename().c_str(), false, &filename_key); + Incremental_archive_entry* entry = + new Incremental_archive_entry(filename_key, arg_serial, mtime); + arch->set_incremental_info(entry); + + if (script_info != NULL) + { + Incremental_script_entry* script_entry = script_info->incremental_info(); + gold_assert(script_entry != NULL); + script_entry->add_object(entry); + } +} + +// Visitor class for processing the unused global symbols in a library. +// An instance of this class is passed to the library's +// for_all_unused_symbols() iterator, which will call the visit() +// function for each global symbol defined in each unused library +// member. We add those symbol names to the incremental info for the +// library. + +class Unused_symbol_visitor : public Library_base::Symbol_visitor_base +{ + public: + Unused_symbol_visitor(Incremental_archive_entry* entry, Stringpool* strtab) + : entry_(entry), strtab_(strtab) + { } + + void + visit(const char* sym) + { + Stringpool::Key symbol_key; + this->strtab_->add(sym, true, &symbol_key); + this->entry_->add_unused_global_symbol(symbol_key); + } + + private: + Incremental_archive_entry* entry_; + Stringpool* strtab_; +}; + +// Finish recording the input archive file ARCHIVE. This is called by the +// Add_archive_symbols task after determining which archive members +// to include. + +void +Incremental_inputs::report_archive_end(Library_base* arch) +{ + Incremental_archive_entry* entry = arch->incremental_info(); + + gold_assert(entry != NULL); + this->inputs_.push_back(entry); + + // Collect unused global symbols. + Unused_symbol_visitor v(entry, this->strtab_); + arch->for_all_unused_symbols(&v); +} + +// Record the input object file OBJ. If ARCH is not NULL, attach +// the object file to the archive. This is called by the +// Add_symbols task after finding out the type of the file. + +void +Incremental_inputs::report_object(Object* obj, unsigned int arg_serial, + Library_base* arch, Script_info* script_info) +{ + Stringpool::Key filename_key; + Timespec mtime = obj->get_mtime(); + + // For a file loaded from a script, don't record its argument serial number. + if (script_info != NULL) + arg_serial = 0; + + this->strtab_->add(obj->name().c_str(), false, &filename_key); + + Incremental_input_entry* input_entry; + + this->current_object_ = obj; + + if (!obj->is_dynamic()) + { + this->current_object_entry_ = + new Incremental_object_entry(filename_key, obj, arg_serial, mtime); + input_entry = this->current_object_entry_; + if (arch != NULL) + { + Incremental_archive_entry* arch_entry = arch->incremental_info(); + gold_assert(arch_entry != NULL); + arch_entry->add_object(this->current_object_entry_); + } + } + else + { + this->current_object_entry_ = NULL; + Stringpool::Key soname_key; + Dynobj* dynobj = obj->dynobj(); + gold_assert(dynobj != NULL); + this->strtab_->add(dynobj->soname(), false, &soname_key); + input_entry = new Incremental_dynobj_entry(filename_key, soname_key, obj, + arg_serial, mtime); + } + + if (obj->is_in_system_directory()) + input_entry->set_is_in_system_directory(); + + if (obj->as_needed()) + input_entry->set_as_needed(); + + this->inputs_.push_back(input_entry); + + if (script_info != NULL) + { + Incremental_script_entry* script_entry = script_info->incremental_info(); + gold_assert(script_entry != NULL); + script_entry->add_object(input_entry); + } +} + +// Record an input section SHNDX from object file OBJ. + +void +Incremental_inputs::report_input_section(Object* obj, unsigned int shndx, + const char* name, off_t sh_size) +{ + Stringpool::Key key = 0; + + if (name != NULL) + this->strtab_->add(name, true, &key); + + gold_assert(obj == this->current_object_); + gold_assert(this->current_object_entry_ != NULL); + this->current_object_entry_->add_input_section(shndx, key, sh_size); +} + +// Record a kept COMDAT group belonging to object file OBJ. + +void +Incremental_inputs::report_comdat_group(Object* obj, const char* name) +{ + Stringpool::Key key = 0; + + if (name != NULL) + this->strtab_->add(name, true, &key); + gold_assert(obj == this->current_object_); + gold_assert(this->current_object_entry_ != NULL); + this->current_object_entry_->add_comdat_group(key); +} + +// Record that the input argument INPUT is a script SCRIPT. This is +// called by read_script after parsing the script and reading the list +// of inputs added by this script. + +void +Incremental_inputs::report_script(Script_info* script, + unsigned int arg_serial, + Timespec mtime) +{ + Stringpool::Key filename_key; + + this->strtab_->add(script->filename().c_str(), false, &filename_key); + Incremental_script_entry* entry = + new Incremental_script_entry(filename_key, arg_serial, script, mtime); + this->inputs_.push_back(entry); + script->set_incremental_info(entry); +} + +// Finalize the incremental link information. Called from +// Layout::finalize. + +void +Incremental_inputs::finalize() +{ + // Finalize the string table. + this->strtab_->set_string_offsets(); +} + +// Create the .gnu_incremental_inputs, _symtab, and _relocs input sections. + +void +Incremental_inputs::create_data_sections(Symbol_table* symtab) +{ + int reloc_align = 4; + + switch (parameters->size_and_endianness()) + { +#ifdef HAVE_TARGET_32_LITTLE + case Parameters::TARGET_32_LITTLE: + this->inputs_section_ = + 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); + 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); + 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); + reloc_align = 8; + break; +#endif + default: + gold_unreachable(); + } + this->symtab_section_ = new Output_data_space(4, "** incremental_symtab"); + this->relocs_section_ = new Output_data_space(reloc_align, + "** incremental_relocs"); + this->got_plt_section_ = new Output_data_space(4, "** incremental_got_plt"); +} + +// Return the sh_entsize value for the .gnu_incremental_relocs section. +unsigned int +Incremental_inputs::relocs_entsize() const +{ + return 8 + 2 * parameters->target().get_size() / 8; +} + +// Class Output_section_incremental_inputs. + +// Finalize the offsets for each input section and supplemental info block, +// and set the final data size of the incremental output sections. + +template +void +Output_section_incremental_inputs::set_final_data_size() +{ + const Incremental_inputs* inputs = this->inputs_; + + // Offset of each input entry. + unsigned int input_offset = this->header_size; + + // Offset of each supplemental info block. + unsigned int file_index = 0; + unsigned int info_offset = this->header_size; + info_offset += this->input_entry_size * inputs->input_file_count(); + + // Count each input file and its supplemental information block. + for (Incremental_inputs::Input_list::const_iterator p = + inputs->input_files().begin(); + p != inputs->input_files().end(); + ++p) + { + // Set the index and offset of the input file entry. + (*p)->set_offset(file_index, input_offset); + ++file_index; + input_offset += this->input_entry_size; + + // Set the offset of the supplemental info block. + switch ((*p)->type()) + { + case INCREMENTAL_INPUT_SCRIPT: + { + Incremental_script_entry *entry = (*p)->script_entry(); + gold_assert(entry != NULL); + (*p)->set_info_offset(info_offset); + // Object count. + info_offset += 4; + // Each member. + info_offset += (entry->get_object_count() * 4); + } + break; + case INCREMENTAL_INPUT_OBJECT: + case INCREMENTAL_INPUT_ARCHIVE_MEMBER: + { + Incremental_object_entry* entry = (*p)->object_entry(); + gold_assert(entry != NULL); + (*p)->set_info_offset(info_offset); + // Input section count, global symbol count, local symbol offset, + // local symbol count, first dynamic reloc, dynamic reloc count, + // comdat group count. + info_offset += this->object_info_size; + // Each input section. + info_offset += (entry->get_input_section_count() + * this->input_section_entry_size); + // Each global symbol. + const Object::Symbols* syms = entry->object()->get_global_symbols(); + info_offset += syms->size() * this->global_sym_entry_size; + // Each comdat group. + info_offset += entry->get_comdat_group_count() * 4; + } + break; + case INCREMENTAL_INPUT_SHARED_LIBRARY: + { + Incremental_dynobj_entry* entry = (*p)->dynobj_entry(); + gold_assert(entry != NULL); + (*p)->set_info_offset(info_offset); + // Global symbol count, soname index. + info_offset += 8; + // Each global symbol. + const Object::Symbols* syms = entry->object()->get_global_symbols(); + gold_assert(syms != NULL); + unsigned int nsyms = syms->size(); + unsigned int nsyms_out = 0; + for (unsigned int i = 0; i < nsyms; ++i) + { + const Symbol* sym = (*syms)[i]; + if (sym == NULL) + continue; + if (sym->is_forwarder()) + sym = this->symtab_->resolve_forwards(sym); + if (sym->symtab_index() != -1U) + ++nsyms_out; + } + info_offset += nsyms_out * 4; + } + break; + case INCREMENTAL_INPUT_ARCHIVE: + { + Incremental_archive_entry* entry = (*p)->archive_entry(); + gold_assert(entry != NULL); + (*p)->set_info_offset(info_offset); + // Member count + unused global symbol count. + info_offset += 8; + // Each member. + info_offset += (entry->get_member_count() * 4); + // Each global symbol. + info_offset += (entry->get_unused_global_symbol_count() * 4); + } + break; + default: + gold_unreachable(); + } + + // Pad so each supplemental info block begins at an 8-byte boundary. + if (info_offset & 4) + info_offset += 4; + } + + this->set_data_size(info_offset); + + // Set the size of the .gnu_incremental_symtab section. + inputs->symtab_section()->set_current_data_size(this->symtab_->output_count() + * sizeof(unsigned int)); + + // Set the size of the .gnu_incremental_relocs section. + inputs->relocs_section()->set_current_data_size(inputs->get_reloc_count() + * this->incr_reloc_size); + + // Set the size of the .gnu_incremental_got_plt section. + Sized_target* target = + parameters->sized_target(); + unsigned int got_count = target->got_entry_count(); + unsigned int plt_count = target->plt_entry_count(); + unsigned int got_plt_size = 8; // GOT entry count, PLT entry count. + got_plt_size = (got_plt_size + got_count + 3) & ~3; // GOT type array. + got_plt_size += got_count * 8 + plt_count * 4; // GOT array, PLT array. + inputs->got_plt_section()->set_current_data_size(got_plt_size); +} + +// Write the contents of the .gnu_incremental_inputs and +// .gnu_incremental_symtab sections. + +template +void +Output_section_incremental_inputs::do_write(Output_file* of) +{ + const Incremental_inputs* inputs = this->inputs_; + Stringpool* strtab = inputs->get_stringpool(); + + // Get a view into the .gnu_incremental_inputs section. + const off_t off = this->offset(); + const off_t oview_size = this->data_size(); + unsigned char* const oview = of->get_output_view(off, oview_size); + unsigned char* pov = oview; + + // Get a view into the .gnu_incremental_symtab section. + const off_t symtab_off = inputs->symtab_section()->offset(); + const off_t symtab_size = inputs->symtab_section()->data_size(); + unsigned char* const symtab_view = of->get_output_view(symtab_off, + symtab_size); + + // Allocate an array of linked list heads for the .gnu_incremental_symtab + // section. Each element corresponds to a global symbol in the output + // symbol table, and points to the head of the linked list that threads + // through the object file input entries. The value of each element + // is the section-relative offset to a global symbol entry in a + // supplemental information block. + unsigned int global_sym_count = this->symtab_->output_count(); + unsigned int* global_syms = new unsigned int[global_sym_count]; + memset(global_syms, 0, global_sym_count * sizeof(unsigned int)); + + // Write the section header. + Stringpool::Key command_line_key = inputs->command_line_key(); + pov = this->write_header(pov, inputs->input_file_count(), + strtab->get_offset_from_key(command_line_key)); + + // Write the list of input files. + pov = this->write_input_files(oview, pov, strtab); + + // Write the supplemental information blocks for each input file. + pov = this->write_info_blocks(oview, pov, strtab, global_syms, + global_sym_count); + + gold_assert(pov - oview == oview_size); + + // Write the .gnu_incremental_symtab section. + gold_assert(static_cast(global_sym_count) * 4 == symtab_size); + this->write_symtab(symtab_view, global_syms, global_sym_count); + + delete[] global_syms; + + // Write the .gnu_incremental_got_plt section. + const off_t got_plt_off = inputs->got_plt_section()->offset(); + const off_t got_plt_size = inputs->got_plt_section()->data_size(); + unsigned char* const got_plt_view = of->get_output_view(got_plt_off, + got_plt_size); + this->write_got_plt(got_plt_view, got_plt_size); + + of->write_output_view(off, oview_size, oview); + of->write_output_view(symtab_off, symtab_size, symtab_view); + of->write_output_view(got_plt_off, got_plt_size, got_plt_view); +} + +// Write the section header: version, input file count, offset of command line +// in the string table, and 4 bytes of padding. + +template +unsigned char* +Output_section_incremental_inputs::write_header( + unsigned char* pov, + unsigned int input_file_count, + section_offset_type command_line_offset) +{ + Swap32::writeval(pov, INCREMENTAL_LINK_VERSION); + Swap32::writeval(pov + 4, input_file_count); + Swap32::writeval(pov + 8, command_line_offset); + Swap32::writeval(pov + 12, 0); + gold_assert(this->header_size == 16); + return pov + this->header_size; +} + +// Write the input file entries. + +template +unsigned char* +Output_section_incremental_inputs::write_input_files( + unsigned char* oview, + unsigned char* pov, + Stringpool* strtab) +{ + const Incremental_inputs* inputs = this->inputs_; + + for (Incremental_inputs::Input_list::const_iterator p = + inputs->input_files().begin(); + p != inputs->input_files().end(); + ++p) + { + gold_assert(static_cast(pov - oview) == (*p)->get_offset()); + section_offset_type filename_offset = + 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; + if ((*p)->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); + Swap32::writeval(pov + 16, mtime.nanoseconds); + Swap16::writeval(pov + 20, flags); + Swap16::writeval(pov + 22, (*p)->arg_serial()); + gold_assert(this->input_entry_size == 24); + pov += this->input_entry_size; + } + return pov; +} + +// Write the supplemental information blocks. + +template +unsigned char* +Output_section_incremental_inputs::write_info_blocks( + unsigned char* oview, + unsigned char* pov, + Stringpool* strtab, + unsigned int* global_syms, + unsigned int global_sym_count) +{ + const Incremental_inputs* inputs = this->inputs_; + unsigned int first_global_index = this->symtab_->first_global_index(); + + for (Incremental_inputs::Input_list::const_iterator p = + inputs->input_files().begin(); + p != inputs->input_files().end(); + ++p) + { + switch ((*p)->type()) + { + case INCREMENTAL_INPUT_SCRIPT: + { + gold_assert(static_cast(pov - oview) + == (*p)->get_info_offset()); + Incremental_script_entry* entry = (*p)->script_entry(); + gold_assert(entry != NULL); + + // Write the object count. + unsigned int nobjects = entry->get_object_count(); + Swap32::writeval(pov, nobjects); + pov += 4; + + // For each object, write the offset to its input file entry. + for (unsigned int i = 0; i < nobjects; ++i) + { + Incremental_input_entry* obj = entry->get_object(i); + Swap32::writeval(pov, obj->get_offset()); + pov += 4; + } + } + break; + + case INCREMENTAL_INPUT_OBJECT: + case INCREMENTAL_INPUT_ARCHIVE_MEMBER: + { + gold_assert(static_cast(pov - oview) + == (*p)->get_info_offset()); + Incremental_object_entry* entry = (*p)->object_entry(); + gold_assert(entry != NULL); + const Object* obj = entry->object(); + const Relobj* relobj = static_cast(obj); + const Object::Symbols* syms = obj->get_global_symbols(); + // Write the input section count and global symbol count. + unsigned int nsections = entry->get_input_section_count(); + unsigned int nsyms = syms->size(); + off_t locals_offset = relobj->local_symbol_offset(); + unsigned int nlocals = relobj->output_local_symbol_count(); + unsigned int first_dynrel = relobj->first_dyn_reloc(); + unsigned int ndynrel = relobj->dyn_reloc_count(); + unsigned int ncomdat = entry->get_comdat_group_count(); + Swap32::writeval(pov, nsections); + Swap32::writeval(pov + 4, nsyms); + Swap32::writeval(pov + 8, static_cast(locals_offset)); + Swap32::writeval(pov + 12, nlocals); + Swap32::writeval(pov + 16, first_dynrel); + Swap32::writeval(pov + 20, ndynrel); + Swap32::writeval(pov + 24, ncomdat); + Swap32::writeval(pov + 28, 0); + gold_assert(this->object_info_size == 32); + pov += this->object_info_size; + + // Build a temporary array to map input section indexes + // from the original object file index to the index in the + // incremental info table. + unsigned int* index_map = new unsigned int[obj->shnum()]; + memset(index_map, 0, obj->shnum() * sizeof(unsigned int)); + + // For each input section, write the name, output section index, + // offset within output section, and input section size. + for (unsigned int i = 0; i < nsections; i++) + { + unsigned int shndx = entry->get_input_section_index(i); + index_map[shndx] = i + 1; + Stringpool::Key key = entry->get_input_section_name_key(i); + off_t name_offset = 0; + if (key != 0) + name_offset = strtab->get_offset_from_key(key); + int out_shndx = 0; + off_t out_offset = 0; + off_t sh_size = 0; + Output_section* os = obj->output_section(shndx); + if (os != NULL) + { + out_shndx = os->out_shndx(); + out_offset = obj->output_section_offset(shndx); + sh_size = entry->get_input_section_size(i); + } + Swap32::writeval(pov, name_offset); + Swap32::writeval(pov + 4, out_shndx); + Swap::writeval(pov + 8, out_offset); + Swap::writeval(pov + 8 + sizeof_addr, sh_size); + gold_assert(this->input_section_entry_size + == 8 + 2 * sizeof_addr); + pov += this->input_section_entry_size; + } + + // For each global symbol, write its associated relocations, + // add it to the linked list of globals, then write the + // supplemental information: global symbol table index, + // input section index, linked list chain pointer, relocation + // count, and offset to the relocations. + for (unsigned int i = 0; i < nsyms; i++) + { + const Symbol* sym = (*syms)[i]; + if (sym->is_forwarder()) + sym = this->symtab_->resolve_forwards(sym); + unsigned int shndx = 0; + if (sym->source() != Symbol::FROM_OBJECT) + { + // The symbol was defined by the linker (e.g., common). + // We mark these symbols with a special SHNDX of -1, + // but exclude linker-predefined symbols and symbols + // copied from shared objects. + if (!sym->is_predefined() + && !sym->is_copied_from_dynobj()) + shndx = -1U; + } + else if (sym->object() == obj && sym->is_defined()) + { + bool is_ordinary; + unsigned int orig_shndx = sym->shndx(&is_ordinary); + if (is_ordinary) + shndx = index_map[orig_shndx]; + else + shndx = 1; + } + unsigned int symtab_index = sym->symtab_index(); + unsigned int chain = 0; + unsigned int first_reloc = 0; + unsigned int nrelocs = obj->get_incremental_reloc_count(i); + if (nrelocs > 0) + { + gold_assert(symtab_index != -1U + && (symtab_index - first_global_index + < global_sym_count)); + first_reloc = obj->get_incremental_reloc_base(i); + chain = global_syms[symtab_index - first_global_index]; + global_syms[symtab_index - first_global_index] = + pov - oview; + } + Swap32::writeval(pov, symtab_index); + Swap32::writeval(pov + 4, shndx); + Swap32::writeval(pov + 8, chain); + Swap32::writeval(pov + 12, nrelocs); + Swap32::writeval(pov + 16, + first_reloc * (8 + 2 * sizeof_addr)); + gold_assert(this->global_sym_entry_size == 20); + pov += this->global_sym_entry_size; + } + + // For each kept COMDAT group, write the group signature. + for (unsigned int i = 0; i < ncomdat; i++) + { + Stringpool::Key key = entry->get_comdat_signature_key(i); + off_t name_offset = 0; + if (key != 0) + name_offset = strtab->get_offset_from_key(key); + Swap32::writeval(pov, name_offset); + pov += 4; + } + + delete[] index_map; + } + break; + + case INCREMENTAL_INPUT_SHARED_LIBRARY: + { + gold_assert(static_cast(pov - oview) + == (*p)->get_info_offset()); + Incremental_dynobj_entry* entry = (*p)->dynobj_entry(); + gold_assert(entry != NULL); + Object* obj = entry->object(); + Dynobj* dynobj = obj->dynobj(); + gold_assert(dynobj != NULL); + const Object::Symbols* syms = obj->get_global_symbols(); + + // Write the soname string table index. + section_offset_type soname_offset = + strtab->get_offset_from_key(entry->get_soname_key()); + Swap32::writeval(pov, soname_offset); + pov += 4; + + // Skip the global symbol count for now. + unsigned char* orig_pov = pov; + pov += 4; + + // For each global symbol, write the global symbol table index. + unsigned int nsyms = syms->size(); + unsigned int nsyms_out = 0; + for (unsigned int i = 0; i < nsyms; i++) + { + const Symbol* sym = (*syms)[i]; + if (sym == NULL) + continue; + if (sym->is_forwarder()) + sym = this->symtab_->resolve_forwards(sym); + 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 + // try to resolve it during an incremental update. + if (sym->visibility() == elfcpp::STV_HIDDEN + || sym->visibility() == elfcpp::STV_INTERNAL) + flags = INCREMENTAL_SHLIB_SYM_DEF; + else if (sym->source() == Symbol::FROM_OBJECT + && sym->object() == obj + && sym->is_defined()) + flags = INCREMENTAL_SHLIB_SYM_DEF; + else if (sym->is_copied_from_dynobj() + && this->symtab_->get_copy_source(sym) == dynobj) + flags = INCREMENTAL_SHLIB_SYM_COPY; + flags <<= INCREMENTAL_SHLIB_SYM_FLAGS_SHIFT; + Swap32::writeval(pov, sym->symtab_index() | flags); + pov += 4; + ++nsyms_out; + } + + // Now write the global symbol count. + Swap32::writeval(orig_pov, nsyms_out); + } + break; + + case INCREMENTAL_INPUT_ARCHIVE: + { + gold_assert(static_cast(pov - oview) + == (*p)->get_info_offset()); + Incremental_archive_entry* entry = (*p)->archive_entry(); + gold_assert(entry != NULL); + + // Write the member count and unused global symbol count. + unsigned int nmembers = entry->get_member_count(); + unsigned int nsyms = entry->get_unused_global_symbol_count(); + Swap32::writeval(pov, nmembers); + Swap32::writeval(pov + 4, nsyms); + pov += 8; + + // For each member, write the offset to its input file entry. + for (unsigned int i = 0; i < nmembers; ++i) + { + Incremental_object_entry* member = entry->get_member(i); + Swap32::writeval(pov, member->get_offset()); + pov += 4; + } + + // For each global symbol, write the name offset. + for (unsigned int i = 0; i < nsyms; ++i) + { + Stringpool::Key key = entry->get_unused_global_symbol(i); + Swap32::writeval(pov, strtab->get_offset_from_key(key)); + pov += 4; + } + } + break; + + default: + gold_unreachable(); + } + + // Pad the info block to a multiple of 8 bytes. + if (static_cast(pov - oview) & 4) + { + Swap32::writeval(pov, 0); + pov += 4; + } + } + return pov; +} + +// Write the contents of the .gnu_incremental_symtab section. + +template +void +Output_section_incremental_inputs::write_symtab( + unsigned char* pov, + unsigned int* global_syms, + unsigned int global_sym_count) +{ + for (unsigned int i = 0; i < global_sym_count; ++i) + { + Swap32::writeval(pov, global_syms[i]); + pov += 4; + } +} + +// This struct holds the view information needed to write the +// .gnu_incremental_got_plt section. + +struct Got_plt_view_info +{ + // Start of the GOT type array in the output view. + unsigned char* got_type_p; + // Start of the GOT descriptor array in the output view. + unsigned char* got_desc_p; + // Start of the PLT descriptor array in the output view. + unsigned char* plt_desc_p; + // Number of GOT entries. + unsigned int got_count; + // Number of PLT entries. + unsigned int plt_count; + // Offset of the first non-reserved PLT entry (this is a target-dependent value). + unsigned int first_plt_entry_offset; + // Size of a PLT entry (this is a target-dependent value). + unsigned int plt_entry_size; + // Symbol index to write in the GOT descriptor array. For global symbols, + // this is the global symbol table index; for local symbols, it is the + // local symbol table index. + unsigned int sym_index; + // Input file index to write in the GOT descriptor array. For global + // symbols, this is 0; for local symbols, it is the index of the input + // file entry in the .gnu_incremental_inputs section. + unsigned int input_index; +}; + +// Functor class for processing a GOT offset list for local symbols. +// Writes the GOT type and symbol index into the GOT type and descriptor +// arrays in the output section. + +template +class Local_got_offset_visitor : public Got_offset_list::Visitor +{ + public: + Local_got_offset_visitor(struct Got_plt_view_info& info) + : info_(info) + { } + + void + visit(unsigned int got_type, unsigned int got_offset) + { + unsigned int got_index = got_offset / this->got_entry_size_; + gold_assert(got_index < this->info_.got_count); + // We can only handle GOT entry types in the range 0..0x7e + // because we use a byte array to store them, and we use the + // high bit to flag a local symbol. + gold_assert(got_type < 0x7f); + this->info_.got_type_p[got_index] = got_type | 0x80; + unsigned char* pov = this->info_.got_desc_p + got_index * 8; + elfcpp::Swap<32, big_endian>::writeval(pov, this->info_.sym_index); + elfcpp::Swap<32, big_endian>::writeval(pov + 4, this->info_.input_index); + } + + private: + static const unsigned int got_entry_size_ = size / 8; + struct Got_plt_view_info& info_; +}; + +// Functor class for processing a GOT offset list. Writes the GOT type +// and symbol index into the GOT type and descriptor arrays in the output +// section. + +template +class Global_got_offset_visitor : public Got_offset_list::Visitor +{ + public: + Global_got_offset_visitor(struct Got_plt_view_info& info) + : info_(info) + { } + + void + visit(unsigned int got_type, unsigned int got_offset) + { + unsigned int got_index = got_offset / this->got_entry_size_; + gold_assert(got_index < this->info_.got_count); + // We can only handle GOT entry types in the range 0..0x7e + // because we use a byte array to store them, and we use the + // high bit to flag a local symbol. + gold_assert(got_type < 0x7f); + this->info_.got_type_p[got_index] = got_type; + unsigned char* pov = this->info_.got_desc_p + got_index * 8; + elfcpp::Swap<32, big_endian>::writeval(pov, this->info_.sym_index); + elfcpp::Swap<32, big_endian>::writeval(pov + 4, 0); + } + + private: + static const unsigned int got_entry_size_ = size / 8; + struct Got_plt_view_info& info_; +}; + +// Functor class for processing the global symbol table. Processes the +// GOT offset list for the symbol, and writes the symbol table index +// into the PLT descriptor array in the output section. + +template +class Global_symbol_visitor_got_plt +{ + public: + Global_symbol_visitor_got_plt(struct Got_plt_view_info& info) + : info_(info) + { } + + void + operator()(const Sized_symbol* sym) + { + typedef Global_got_offset_visitor Got_visitor; + 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_); + got_offsets->for_all_got_offsets(&v); + } + if (sym->has_plt_offset()) + { + unsigned int plt_index = + ((sym->plt_offset() - this->info_.first_plt_entry_offset) + / this->info_.plt_entry_size); + gold_assert(plt_index < this->info_.plt_count); + unsigned char* pov = this->info_.plt_desc_p + plt_index * 4; + elfcpp::Swap<32, big_endian>::writeval(pov, sym->symtab_index()); + } + } + + private: + struct Got_plt_view_info& info_; +}; + +// Write the contents of the .gnu_incremental_got_plt section. + +template +void +Output_section_incremental_inputs::write_got_plt( + unsigned char* pov, + off_t view_size) +{ + Sized_target* target = + parameters->sized_target(); + + // Set up the view information for the functors. + struct Got_plt_view_info view_info; + view_info.got_count = target->got_entry_count(); + view_info.plt_count = target->plt_entry_count(); + view_info.first_plt_entry_offset = target->first_plt_entry_offset(); + view_info.plt_entry_size = target->plt_entry_size(); + view_info.got_type_p = pov + 8; + view_info.got_desc_p = (view_info.got_type_p + + ((view_info.got_count + 3) & ~3)); + view_info.plt_desc_p = view_info.got_desc_p + view_info.got_count * 8; + + gold_assert(pov + view_size == + view_info.plt_desc_p + view_info.plt_count * 4); + + // Write the section header. + Swap32::writeval(pov, view_info.got_count); + Swap32::writeval(pov + 4, view_info.plt_count); + + // Initialize the GOT type array to 0xff (reserved). + memset(view_info.got_type_p, 0xff, view_info.got_count); + + // Write the incremental GOT descriptors for local symbols. + typedef Local_got_offset_visitor Got_visitor; + for (Incremental_inputs::Input_list::const_iterator p = + this->inputs_->input_files().begin(); + p != this->inputs_->input_files().end(); + ++p) + { + if ((*p)->type() != INCREMENTAL_INPUT_OBJECT + && (*p)->type() != INCREMENTAL_INPUT_ARCHIVE_MEMBER) + continue; + Incremental_object_entry* entry = (*p)->object_entry(); + gold_assert(entry != NULL); + const Object* obj = entry->object(); + gold_assert(obj != NULL); + view_info.input_index = (*p)->get_file_index(); + Got_visitor v(view_info); + obj->for_all_local_got_entries(&v); + } + + // Write the incremental GOT and PLT descriptors for global symbols. + typedef Global_symbol_visitor_got_plt Symbol_visitor; + symtab_->for_all_symbols(Symbol_visitor(view_info)); +} + +// Class Sized_relobj_incr. Most of these methods are not used for +// Incremental objects, but are required to be implemented by the +// base class Object. + +template +Sized_relobj_incr::Sized_relobj_incr( + const std::string& name, + Sized_incremental_binary* ibase, + unsigned int input_file_index) + : Sized_relobj(name, NULL), ibase_(ibase), + input_file_index_(input_file_index), + input_reader_(ibase->inputs_reader().input_file(input_file_index)), + local_symbol_count_(0), output_local_dynsym_count_(0), + local_symbol_index_(0), local_symbol_offset_(0), local_dynsym_offset_(0), + symbols_(), defined_count_(0), incr_reloc_offset_(-1U), + incr_reloc_count_(0), incr_reloc_output_index_(0), incr_relocs_(NULL), + local_symbols_() +{ + if (this->input_reader_.is_in_system_directory()) + this->set_is_in_system_directory(); + const unsigned int shnum = this->input_reader_.get_input_section_count() + 1; + this->set_shnum(shnum); + ibase->set_input_object(input_file_index, this); +} + +// Read the symbols. + +template +void +Sized_relobj_incr::do_read_symbols(Read_symbols_data*) +{ + gold_unreachable(); +} + +// Lay out the input sections. + +template +void +Sized_relobj_incr::do_layout( + Symbol_table*, + Layout* layout, + Read_symbols_data*) +{ + const unsigned int shnum = this->shnum(); + Incremental_inputs* incremental_inputs = layout->incremental_inputs(); + gold_assert(incremental_inputs != NULL); + Output_sections& out_sections(this->output_sections()); + out_sections.resize(shnum); + this->section_offsets().resize(shnum); + + // Keep track of .debug_info and .debug_types sections. + std::vector debug_info_sections; + std::vector debug_types_sections; + + for (unsigned int i = 1; i < shnum; i++) + { + typename Input_entry_reader::Input_section_info sect = + 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; + Output_section* os = this->ibase_->output_section(sect.output_shndx); + gold_assert(os != NULL); + out_sections[i] = os; + this->section_offsets()[i] = static_cast
(sect.sh_offset); + + // When generating a .gdb_index section, we do additional + // processing of .debug_info and .debug_types sections after all + // the other sections. + if (parameters->options().gdb_index()) + { + const char* name = os->name(); + if (strcmp(name, ".debug_info") == 0) + debug_info_sections.push_back(i); + else if (strcmp(name, ".debug_types") == 0) + debug_types_sections.push_back(i); + } + } + + // Process the COMDAT groups. + unsigned int ncomdat = this->input_reader_.get_comdat_group_count(); + for (unsigned int i = 0; i < ncomdat; i++) + { + const char* signature = this->input_reader_.get_comdat_group_signature(i); + if (signature == NULL || signature[0] == '\0') + 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"), + signature); + } + + // When building a .gdb_index section, scan the .debug_info and + // .debug_types sections. + for (std::vector::const_iterator p + = debug_info_sections.begin(); + p != debug_info_sections.end(); + ++p) + { + unsigned int i = *p; + layout->add_to_gdb_index(false, this, NULL, 0, i, 0, 0); + } + for (std::vector::const_iterator p + = debug_types_sections.begin(); + p != debug_types_sections.end(); + ++p) + { + unsigned int i = *p; + layout->add_to_gdb_index(true, this, 0, 0, i, 0, 0); + } +} + +// Layout sections whose layout was deferred while waiting for +// input files from a plugin. +template +void +Sized_relobj_incr::do_layout_deferred_sections(Layout*) +{ +} + +// Add the symbols to the symbol table. + +template +void +Sized_relobj_incr::do_add_symbols( + Symbol_table* symtab, + Read_symbols_data*, + Layout*) +{ + const int sym_size = elfcpp::Elf_sizes::sym_size; + unsigned char symbuf[sym_size]; + elfcpp::Sym sym(symbuf); + elfcpp::Sym_write osym(symbuf); + + typedef typename elfcpp::Elf_types::Elf_WXword Elf_size_type; + + unsigned int nsyms = this->input_reader_.get_global_symbol_count(); + this->symbols_.resize(nsyms); + + Incremental_binary::View symtab_view(NULL); + unsigned int symtab_count; + elfcpp::Elf_strtab strtab(NULL, 0); + this->ibase_->get_symtab_view(&symtab_view, &symtab_count, &strtab); + + Incremental_symtab_reader isymtab(this->ibase_->symtab_reader()); + unsigned int isym_count = isymtab.symbol_count(); + unsigned int first_global = symtab_count - isym_count; + + const unsigned char* sym_p; + for (unsigned int i = 0; i < nsyms; ++i) + { + Incremental_global_symbol_reader info = + this->input_reader_.get_global_symbol_reader(i); + unsigned int output_symndx = info.output_symndx(); + sym_p = symtab_view.data() + output_symndx * sym_size; + elfcpp::Sym gsym(sym_p); + const char* name; + if (!strtab.get_c_string(gsym.get_st_name(), &name)) + name = ""; + + typename elfcpp::Elf_types::Elf_Addr v = gsym.get_st_value(); + unsigned int shndx = gsym.get_st_shndx(); + elfcpp::STB st_bind = gsym.get_st_bind(); + elfcpp::STT st_type = gsym.get_st_type(); + + // 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; + + unsigned int input_shndx = info.shndx(); + if (input_shndx == 0 || input_shndx == -1U) + { + shndx = elfcpp::SHN_UNDEF; + v = 0; + } + else if (shndx != elfcpp::SHN_ABS) + { + // Find the input section and calculate the section-relative value. + gold_assert(shndx != elfcpp::SHN_UNDEF); + Output_section* os = this->ibase_->output_section(shndx); + gold_assert(os != NULL && os->has_fixed_layout()); + typename Input_entry_reader::Input_section_info sect = + this->input_reader_.get_input_section(input_shndx - 1); + gold_assert(sect.output_shndx == shndx); + if (st_type != elfcpp::STT_TLS) + v -= os->address(); + v -= sect.sh_offset; + shndx = input_shndx; + } + + osym.put_st_name(0); + osym.put_st_value(v); + osym.put_st_size(gsym.get_st_size()); + osym.put_st_info(st_bind, st_type); + osym.put_st_other(gsym.get_st_other()); + osym.put_st_shndx(shndx); + + Symbol* res = symtab->add_from_incrobj(this, name, NULL, &sym); + + if (shndx != elfcpp::SHN_UNDEF) + ++this->defined_count_; + + // If this is a linker-defined symbol that hasn't yet been defined, + // define it now. + if (input_shndx == -1U && !res->is_defined()) + { + shndx = gsym.get_st_shndx(); + v = gsym.get_st_value(); + Elf_size_type symsize = gsym.get_st_size(); + if (shndx == elfcpp::SHN_ABS) + { + symtab->define_as_constant(name, NULL, + Symbol_table::INCREMENTAL_BASE, + v, symsize, st_type, st_bind, + gsym.get_st_visibility(), 0, + false, false); + } + else + { + Output_section* os = this->ibase_->output_section(shndx); + gold_assert(os != NULL && os->has_fixed_layout()); + v -= os->address(); + if (symsize > 0) + os->reserve(v, symsize); + symtab->define_in_output_data(name, NULL, + Symbol_table::INCREMENTAL_BASE, + os, v, symsize, st_type, st_bind, + gsym.get_st_visibility(), 0, + false, false); + } + } + + this->symbols_[i] = res; + this->ibase_->add_global_symbol(output_symndx - first_global, res); + } +} + +// Return TRUE if we should include this object from an archive library. + +template +Archive::Should_include +Sized_relobj_incr::do_should_include_member( + Symbol_table*, + Layout*, + Read_symbols_data*, + std::string*) +{ + gold_unreachable(); +} + +// Iterate over global symbols, calling a visitor class V for each. + +template +void +Sized_relobj_incr::do_for_all_global_symbols( + Read_symbols_data*, + Library_base::Symbol_visitor_base*) +{ + // This routine is not used for incremental objects. +} + +// Get the size of a section. + +template +uint64_t +Sized_relobj_incr::do_section_size(unsigned int) +{ + gold_unreachable(); +} + +// Get the name of a section. This returns the name of the output +// section, because we don't usually track the names of the input +// sections. + +template +std::string +Sized_relobj_incr::do_section_name(unsigned int shndx) +{ + Output_sections& out_sections(this->output_sections()); + Output_section* os = out_sections[shndx]; + if (os == NULL) + return NULL; + return os->name(); +} + +// Return a view of the contents of a section. + +template +const unsigned char* +Sized_relobj_incr::do_section_contents( + unsigned int shndx, + section_size_type* plen, + bool) +{ + Output_sections& out_sections(this->output_sections()); + Output_section* os = out_sections[shndx]; + gold_assert(os != NULL); + off_t section_offset = os->offset(); + typename Input_entry_reader::Input_section_info sect = + this->input_reader_.get_input_section(shndx - 1); + section_offset += sect.sh_offset; + *plen = sect.sh_size; + return this->ibase_->view(section_offset, sect.sh_size).data(); +} + +// Return section flags. + +template +uint64_t +Sized_relobj_incr::do_section_flags(unsigned int) +{ + gold_unreachable(); +} + +// Return section entsize. + +template +uint64_t +Sized_relobj_incr::do_section_entsize(unsigned int) +{ + gold_unreachable(); +} + +// Return section address. + +template +uint64_t +Sized_relobj_incr::do_section_address(unsigned int) +{ + gold_unreachable(); +} + +// Return section type. + +template +unsigned int +Sized_relobj_incr::do_section_type(unsigned int) +{ + gold_unreachable(); +} + +// Return the section link field. + +template +unsigned int +Sized_relobj_incr::do_section_link(unsigned int) +{ + gold_unreachable(); +} + +// Return the section link field. + +template +unsigned int +Sized_relobj_incr::do_section_info(unsigned int) +{ + gold_unreachable(); +} + +// Return the section alignment. + +template +uint64_t +Sized_relobj_incr::do_section_addralign(unsigned int) +{ + gold_unreachable(); +} + +// Return the Xindex structure to use. + +template +Xindex* +Sized_relobj_incr::do_initialize_xindex() +{ + gold_unreachable(); +} + +// Get symbol counts. + +template +void +Sized_relobj_incr::do_get_global_symbol_counts( + const Symbol_table*, + size_t* defined, + size_t* used) const +{ + *defined = this->defined_count_; + size_t count = 0; + for (typename Symbols::const_iterator p = this->symbols_.begin(); + p != this->symbols_.end(); + ++p) + if (*p != NULL + && (*p)->source() == Symbol::FROM_OBJECT + && (*p)->object() == this + && (*p)->is_defined()) + ++count; + *used = count; +} + +// Read the relocs. + +template +void +Sized_relobj_incr::do_read_relocs(Read_relocs_data*) +{ +} + +// Process the relocs to find list of referenced sections. Used only +// during garbage collection. + +template +void +Sized_relobj_incr::do_gc_process_relocs(Symbol_table*, + Layout*, + Read_relocs_data*) +{ + gold_unreachable(); +} + +// Scan the relocs and adjust the symbol table. + +template +void +Sized_relobj_incr::do_scan_relocs(Symbol_table*, + Layout* layout, + Read_relocs_data*) +{ + // Count the incremental relocations for this object. + unsigned int nsyms = this->input_reader_.get_global_symbol_count(); + this->allocate_incremental_reloc_counts(); + for (unsigned int i = 0; i < nsyms; i++) + { + Incremental_global_symbol_reader sym = + this->input_reader_.get_global_symbol_reader(i); + unsigned int reloc_count = sym.reloc_count(); + if (reloc_count > 0 && this->incr_reloc_offset_ == -1U) + this->incr_reloc_offset_ = sym.reloc_offset(); + this->incr_reloc_count_ += reloc_count; + for (unsigned int j = 0; j < reloc_count; j++) + this->count_incremental_reloc(i); + } + this->incr_reloc_output_index_ = + layout->incremental_inputs()->get_reloc_count(); + this->finalize_incremental_relocs(layout, false); + + // The incoming incremental relocations may not end up in the same + // location after the incremental update, because the incremental info + // is regenerated in each link. Because the new location may overlap + // with other data in the updated output file, we need to copy the + // relocations into a buffer so that we can still read them safely + // after we start writing updates to the output file. + if (this->incr_reloc_count_ > 0) + { + const Incremental_relocs_reader& relocs_reader = + this->ibase_->relocs_reader(); + const unsigned int incr_reloc_size = relocs_reader.reloc_size; + unsigned int len = this->incr_reloc_count_ * incr_reloc_size; + this->incr_relocs_ = new unsigned char[len]; + memcpy(this->incr_relocs_, + relocs_reader.data(this->incr_reloc_offset_), + len); + } +} + +// Count the local symbols. + +template +void +Sized_relobj_incr::do_count_local_symbols( + Stringpool_template* pool, + Stringpool_template*) +{ + const int sym_size = elfcpp::Elf_sizes::sym_size; + + // Set the count of local symbols based on the incremental info. + unsigned int nlocals = this->input_reader_.get_local_symbol_count(); + this->local_symbol_count_ = nlocals; + this->local_symbols_.reserve(nlocals); + + // Get views of the base file's symbol table and string table. + Incremental_binary::View symtab_view(NULL); + unsigned int symtab_count; + elfcpp::Elf_strtab strtab(NULL, 0); + this->ibase_->get_symtab_view(&symtab_view, &symtab_count, &strtab); + + // Read the local symbols from the base file's symbol table. + off_t off = this->input_reader_.get_local_symbol_offset(); + const unsigned char* symp = symtab_view.data() + off; + for (unsigned int i = 0; i < nlocals; ++i, symp += sym_size) + { + elfcpp::Sym sym(symp); + const char* name; + if (!strtab.get_c_string(sym.get_st_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, + sym.get_st_value(), + sym.get_st_size(), + sym.get_st_shndx(), + sym.get_st_type(), + false)); + } +} + +// Finalize the local symbols. + +template +unsigned int +Sized_relobj_incr::do_finalize_local_symbols( + unsigned int index, + off_t off, + Symbol_table*) +{ + this->local_symbol_index_ = index; + this->local_symbol_offset_ = off; + return index + this->local_symbol_count_; +} + +// Set the offset where local dynamic symbol information will be stored. + +template +unsigned int +Sized_relobj_incr::do_set_local_dynsym_indexes( + unsigned int index) +{ + // FIXME: set local dynsym indexes. + return index; +} + +// Set the offset where local dynamic symbol information will be stored. + +template +unsigned int +Sized_relobj_incr::do_set_local_dynsym_offset(off_t) +{ + return 0; +} + +// Relocate the input sections and write out the local symbols. +// We don't actually do any relocation here. For unchanged input files, +// we reapply relocations only for symbols that have changed; that happens +// in queue_final_tasks. We do need to rewrite the incremental relocations +// for this object. + +template +void +Sized_relobj_incr::do_relocate(const Symbol_table*, + const Layout* layout, + Output_file* of) +{ + if (this->incr_reloc_count_ == 0) + return; + + const unsigned int incr_reloc_size = + Incremental_relocs_reader::reloc_size; + + // Get a view for the .gnu_incremental_relocs section. + Incremental_inputs* inputs = layout->incremental_inputs(); + gold_assert(inputs != NULL); + const off_t relocs_off = inputs->relocs_section()->offset(); + const off_t relocs_size = inputs->relocs_section()->data_size(); + unsigned char* const view = of->get_output_view(relocs_off, relocs_size); + + // Copy the relocations from the buffer. + off_t off = this->incr_reloc_output_index_ * incr_reloc_size; + unsigned int len = this->incr_reloc_count_ * incr_reloc_size; + memcpy(view + off, this->incr_relocs_, len); + + // The output section table may have changed, so we need to map + // the old section index to the new section index for each relocation. + for (unsigned int i = 0; i < this->incr_reloc_count_; ++i) + { + unsigned char* pov = view + off + i * incr_reloc_size; + unsigned int shndx = elfcpp::Swap<32, big_endian>::readval(pov + 4); + Output_section* os = this->ibase_->output_section(shndx); + gold_assert(os != NULL); + shndx = os->out_shndx(); + elfcpp::Swap<32, big_endian>::writeval(pov + 4, shndx); + } + + of->write_output_view(off, len, view); + + // Get views into the output file for the portions of the symbol table + // and the dynamic symbol table that we will be writing. + off_t symtab_off = layout->symtab_section()->offset(); + off_t output_size = this->local_symbol_count_ * This::sym_size; + unsigned char* oview = NULL; + if (output_size > 0) + oview = of->get_output_view(symtab_off + this->local_symbol_offset_, + output_size); + + off_t dyn_output_size = this->output_local_dynsym_count_ * sym_size; + unsigned char* dyn_oview = NULL; + if (dyn_output_size > 0) + dyn_oview = of->get_output_view(this->local_dynsym_offset_, + dyn_output_size); + + // Write the local symbols. + unsigned char* ov = oview; + unsigned char* dyn_ov = dyn_oview; + const Stringpool* sympool = layout->sympool(); + const Stringpool* dynpool = layout->dynpool(); + Output_symtab_xindex* symtab_xindex = layout->symtab_xindex(); + Output_symtab_xindex* dynsym_xindex = layout->dynsym_xindex(); + for (unsigned int i = 0; i < this->local_symbol_count_; ++i) + { + Local_symbol& lsym(this->local_symbols_[i]); + + bool is_ordinary; + unsigned int st_shndx = this->adjust_sym_shndx(i, lsym.st_shndx, + &is_ordinary); + if (is_ordinary) + { + Output_section* os = this->ibase_->output_section(st_shndx); + st_shndx = os->out_shndx(); + if (st_shndx >= elfcpp::SHN_LORESERVE) + { + symtab_xindex->add(this->local_symbol_index_ + i, st_shndx); + if (lsym.needs_dynsym_entry) + dynsym_xindex->add(lsym.output_dynsym_index, st_shndx); + st_shndx = elfcpp::SHN_XINDEX; + } + } + + // Write the symbol to the output symbol table. + { + elfcpp::Sym_write osym(ov); + osym.put_st_name(sympool->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(lsym.st_type)); + osym.put_st_other(0); + osym.put_st_shndx(st_shndx); + ov += sym_size; + } + + // 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 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(lsym.st_type)); + osym.put_st_other(0); + osym.put_st_shndx(st_shndx); + dyn_ov += sym_size; + } + } + + if (output_size > 0) + { + gold_assert(ov - oview == output_size); + of->write_output_view(symtab_off + this->local_symbol_offset_, + output_size, oview); + } + + if (dyn_output_size > 0) + { + gold_assert(dyn_ov - dyn_oview == dyn_output_size); + of->write_output_view(this->local_dynsym_offset_, dyn_output_size, + dyn_oview); + } +} + +// Set the offset of a section. + +template +void +Sized_relobj_incr::do_set_section_offset(unsigned int, + uint64_t) +{ +} + +// Class Sized_incr_dynobj. Most of these methods are not used for +// Incremental objects, but are required to be implemented by the +// base class Object. + +template +Sized_incr_dynobj::Sized_incr_dynobj( + const std::string& name, + Sized_incremental_binary* ibase, + unsigned int input_file_index) + : Dynobj(name, NULL), ibase_(ibase), + input_file_index_(input_file_index), + input_reader_(ibase->inputs_reader().input_file(input_file_index)), + symbols_(), defined_count_(0) +{ + if (this->input_reader_.is_in_system_directory()) + this->set_is_in_system_directory(); + if (this->input_reader_.as_needed()) + this->set_as_needed(); + this->set_soname_string(this->input_reader_.get_soname()); + this->set_shnum(0); +} + +// Read the symbols. + +template +void +Sized_incr_dynobj::do_read_symbols(Read_symbols_data*) +{ + gold_unreachable(); +} + +// Lay out the input sections. + +template +void +Sized_incr_dynobj::do_layout( + Symbol_table*, + Layout*, + Read_symbols_data*) +{ +} + +// Add the symbols to the symbol table. + +template +void +Sized_incr_dynobj::do_add_symbols( + Symbol_table* symtab, + Read_symbols_data*, + Layout*) +{ + const int sym_size = elfcpp::Elf_sizes::sym_size; + unsigned char symbuf[sym_size]; + elfcpp::Sym sym(symbuf); + elfcpp::Sym_write osym(symbuf); + + unsigned int nsyms = this->input_reader_.get_global_symbol_count(); + this->symbols_.resize(nsyms); + + Incremental_binary::View symtab_view(NULL); + unsigned int symtab_count; + elfcpp::Elf_strtab strtab(NULL, 0); + this->ibase_->get_symtab_view(&symtab_view, &symtab_count, &strtab); + + Incremental_symtab_reader isymtab(this->ibase_->symtab_reader()); + unsigned int isym_count = isymtab.symbol_count(); + unsigned int first_global = symtab_count - isym_count; + + // We keep a set of symbols that we have generated COPY relocations + // for, indexed by the symbol value. We do not need more than one + // COPY relocation per address. + typedef typename std::set
Copied_symbols; + Copied_symbols copied_symbols; + + const unsigned char* sym_p; + for (unsigned int i = 0; i < nsyms; ++i) + { + bool is_def; + bool is_copy; + unsigned int output_symndx = + this->input_reader_.get_output_symbol_index(i, &is_def, &is_copy); + sym_p = symtab_view.data() + output_symndx * sym_size; + elfcpp::Sym gsym(sym_p); + const char* name; + if (!strtab.get_c_string(gsym.get_st_name(), &name)) + name = ""; + + Address v; + unsigned int shndx; + elfcpp::STB st_bind = gsym.get_st_bind(); + elfcpp::STT st_type = gsym.get_st_type(); + + // 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; + + if (!is_def) + { + shndx = elfcpp::SHN_UNDEF; + v = 0; + } + else + { + // For a symbol defined in a shared object, the section index + // is meaningless, as long as it's not SHN_UNDEF. + shndx = 1; + v = gsym.get_st_value(); + ++this->defined_count_; + } + + osym.put_st_name(0); + osym.put_st_value(v); + osym.put_st_size(gsym.get_st_size()); + osym.put_st_info(st_bind, st_type); + osym.put_st_other(gsym.get_st_other()); + osym.put_st_shndx(shndx); + + Sized_symbol* res = + symtab->add_from_incrobj(this, name, NULL, &sym); + this->symbols_[i] = res; + this->ibase_->add_global_symbol(output_symndx - first_global, + this->symbols_[i]); + + if (is_copy) + { + std::pair ins = + copied_symbols.insert(v); + if (ins.second) + { + unsigned int shndx = gsym.get_st_shndx(); + Output_section* os = this->ibase_->output_section(shndx); + off_t offset = v - os->address(); + this->ibase_->add_copy_reloc(this->symbols_[i], os, offset); + } + } + } +} + +// Return TRUE if we should include this object from an archive library. + +template +Archive::Should_include +Sized_incr_dynobj::do_should_include_member( + Symbol_table*, + Layout*, + Read_symbols_data*, + std::string*) +{ + gold_unreachable(); +} + +// Iterate over global symbols, calling a visitor class V for each. + +template +void +Sized_incr_dynobj::do_for_all_global_symbols( + Read_symbols_data*, + Library_base::Symbol_visitor_base*) +{ + // This routine is not used for dynamic libraries. +} + +// Iterate over local symbols, calling a visitor class V for each GOT offset +// associated with a local symbol. + +template +void +Sized_incr_dynobj::do_for_all_local_got_entries( + Got_offset_list::Visitor*) const +{ +} + +// Get the size of a section. + +template +uint64_t +Sized_incr_dynobj::do_section_size(unsigned int) +{ + gold_unreachable(); +} + +// Get the name of a section. + +template +std::string +Sized_incr_dynobj::do_section_name(unsigned int) +{ + gold_unreachable(); +} + +// Return a view of the contents of a section. + +template +const unsigned char* +Sized_incr_dynobj::do_section_contents( + unsigned int, + section_size_type*, + bool) +{ + gold_unreachable(); +} + +// Return section flags. + +template +uint64_t +Sized_incr_dynobj::do_section_flags(unsigned int) +{ + gold_unreachable(); +} + +// Return section entsize. + +template +uint64_t +Sized_incr_dynobj::do_section_entsize(unsigned int) +{ + gold_unreachable(); +} + +// Return section address. + +template +uint64_t +Sized_incr_dynobj::do_section_address(unsigned int) +{ + gold_unreachable(); +} + +// Return section type. + +template +unsigned int +Sized_incr_dynobj::do_section_type(unsigned int) +{ + gold_unreachable(); +} + +// Return the section link field. + +template +unsigned int +Sized_incr_dynobj::do_section_link(unsigned int) +{ + gold_unreachable(); +} + +// Return the section link field. + +template +unsigned int +Sized_incr_dynobj::do_section_info(unsigned int) +{ + gold_unreachable(); +} + +// Return the section alignment. + +template +uint64_t +Sized_incr_dynobj::do_section_addralign(unsigned int) +{ + gold_unreachable(); +} + +// Return the Xindex structure to use. + +template +Xindex* +Sized_incr_dynobj::do_initialize_xindex() +{ + gold_unreachable(); +} + +// Get symbol counts. + +template +void +Sized_incr_dynobj::do_get_global_symbol_counts( + const Symbol_table*, + size_t* defined, + size_t* used) const +{ + *defined = this->defined_count_; + size_t count = 0; + for (typename Symbols::const_iterator p = this->symbols_.begin(); + p != this->symbols_.end(); + ++p) + if (*p != NULL + && (*p)->source() == Symbol::FROM_OBJECT + && (*p)->object() == this + && (*p)->is_defined() + && (*p)->dynsym_index() != -1U) + ++count; + *used = count; +} + +// Allocate an incremental object of the appropriate size and endianness. + +Object* +make_sized_incremental_object( + Incremental_binary* ibase, + unsigned int input_file_index, + Incremental_input_type input_type, + const Incremental_binary::Input_reader* input_reader) +{ + Object* obj = NULL; + std::string name(input_reader->filename()); + + switch (parameters->size_and_endianness()) + { +#ifdef HAVE_TARGET_32_LITTLE + case Parameters::TARGET_32_LITTLE: + { + Sized_incremental_binary<32, false>* sized_ibase = + static_cast*>(ibase); + if (input_type == INCREMENTAL_INPUT_SHARED_LIBRARY) + obj = new Sized_incr_dynobj<32, false>(name, sized_ibase, + input_file_index); + else + obj = new Sized_relobj_incr<32, false>(name, sized_ibase, + input_file_index); + } + break; +#endif +#ifdef HAVE_TARGET_32_BIG + case Parameters::TARGET_32_BIG: + { + Sized_incremental_binary<32, true>* sized_ibase = + static_cast*>(ibase); + if (input_type == INCREMENTAL_INPUT_SHARED_LIBRARY) + obj = new Sized_incr_dynobj<32, true>(name, sized_ibase, + input_file_index); + else + obj = new Sized_relobj_incr<32, true>(name, sized_ibase, + input_file_index); + } + break; +#endif +#ifdef HAVE_TARGET_64_LITTLE + case Parameters::TARGET_64_LITTLE: + { + Sized_incremental_binary<64, false>* sized_ibase = + static_cast*>(ibase); + if (input_type == INCREMENTAL_INPUT_SHARED_LIBRARY) + obj = new Sized_incr_dynobj<64, false>(name, sized_ibase, + input_file_index); + else + obj = new Sized_relobj_incr<64, false>(name, sized_ibase, + input_file_index); + } + break; +#endif +#ifdef HAVE_TARGET_64_BIG + case Parameters::TARGET_64_BIG: + { + Sized_incremental_binary<64, true>* sized_ibase = + static_cast*>(ibase); + if (input_type == INCREMENTAL_INPUT_SHARED_LIBRARY) + obj = new Sized_incr_dynobj<64, true>(name, sized_ibase, + input_file_index); + else + obj = new Sized_relobj_incr<64, true>(name, sized_ibase, + input_file_index); + } + break; +#endif + default: + gold_unreachable(); + } + + gold_assert(obj != NULL); + return obj; +} + +// Copy the unused symbols from the incremental input info. +// We need to do this because we may be overwriting the incremental +// input info in the base file before we write the new incremental +// info. +void +Incremental_library::copy_unused_symbols() +{ + unsigned int symcount = this->input_reader_->get_unused_symbol_count(); + this->unused_symbols_.reserve(symcount); + for (unsigned int i = 0; i < symcount; ++i) + { + std::string name(this->input_reader_->get_unused_symbol(i)); + this->unused_symbols_.push_back(name); + } +} + +// Iterator for unused global symbols in the library. +void +Incremental_library::do_for_all_unused_symbols(Symbol_visitor_base* v) const +{ + for (Symbol_list::const_iterator p = this->unused_symbols_.begin(); + p != this->unused_symbols_.end(); + ++p) + v->visit(p->c_str()); +} + +// Instantiate the templates we need. + +#ifdef HAVE_TARGET_32_LITTLE +template +class Sized_incremental_binary<32, false>; + +template +class Sized_relobj_incr<32, false>; + +template +class Sized_incr_dynobj<32, false>; +#endif + +#ifdef HAVE_TARGET_32_BIG +template +class Sized_incremental_binary<32, true>; + +template +class Sized_relobj_incr<32, true>; + +template +class Sized_incr_dynobj<32, true>; +#endif + +#ifdef HAVE_TARGET_64_LITTLE +template +class Sized_incremental_binary<64, false>; + +template +class Sized_relobj_incr<64, false>; + +template +class Sized_incr_dynobj<64, false>; +#endif + +#ifdef HAVE_TARGET_64_BIG +template +class Sized_incremental_binary<64, true>; + +template +class Sized_relobj_incr<64, true>; + +template +class Sized_incr_dynobj<64, true>; +#endif + +} // End namespace gold. diff --git a/binutils-2.25/gold/incremental.h b/binutils-2.25/gold/incremental.h new file mode 100644 index 00000000..77803fc1 --- /dev/null +++ b/binutils-2.25/gold/incremental.h @@ -0,0 +1,2255 @@ +// inremental.h -- incremental linking support for gold -*- C++ -*- + +// Copyright 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc. +// Written by Mikolaj Zalewski . + +// 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. + +#ifndef GOLD_INCREMENTAL_H +#define GOLD_INCREMENTAL_H + +#include +#include + +#include "elfcpp_file.h" +#include "stringpool.h" +#include "workqueue.h" +#include "fileread.h" +#include "output.h" +#include "archive.h" + +namespace gold +{ + +class Input_argument; +class Incremental_inputs_checker; +class Incremental_script_entry; +class Incremental_object_entry; +class Incremental_dynobj_entry; +class Incremental_archive_entry; +class Incremental_inputs; +class Incremental_binary; +class Incremental_library; +class Object; + +// Incremental input type as stored in .gnu_incremental_inputs. + +enum Incremental_input_type +{ + INCREMENTAL_INPUT_OBJECT = 1, + INCREMENTAL_INPUT_ARCHIVE_MEMBER = 2, + INCREMENTAL_INPUT_ARCHIVE = 3, + INCREMENTAL_INPUT_SHARED_LIBRARY = 4, + INCREMENTAL_INPUT_SCRIPT = 5 +}; + +// Incremental input file flags. +// The input file type is stored in the lower eight bits. + +enum Incremental_input_flags +{ + INCREMENTAL_INPUT_IN_SYSTEM_DIR = 0x8000, + INCREMENTAL_INPUT_AS_NEEDED = 0x4000 +}; + +// Symbol flags for the incremental symbol table. +// These flags are stored in the top two bits of +// the symbol index field. + +enum Incremental_shlib_symbol_flags +{ + // Symbol is defined in this library. + INCREMENTAL_SHLIB_SYM_DEF = 2, + // Symbol is defined in this library, with a COPY relocation. + INCREMENTAL_SHLIB_SYM_COPY = 3 +}; + +static const int INCREMENTAL_SHLIB_SYM_FLAGS_SHIFT = 30; + +// Return TRUE if a section of type SH_TYPE can be updated in place +// during an incremental update. +bool +can_incremental_update(unsigned int sh_type); + +// Create an Incremental_binary object for FILE. Returns NULL is this is not +// possible, e.g. FILE is not an ELF file or has an unsupported target. + +Incremental_binary* +open_incremental_binary(Output_file* file); + +// Base class for recording each input file. + +class Incremental_input_entry +{ + public: + Incremental_input_entry(Stringpool::Key filename_key, unsigned int arg_serial, + Timespec mtime) + : filename_key_(filename_key), file_index_(0), offset_(0), info_offset_(0), + arg_serial_(arg_serial), mtime_(mtime), is_in_system_directory_(false), + as_needed_(false) + { } + + virtual + ~Incremental_input_entry() + { } + + // Return the type of input file. + Incremental_input_type + type() const + { return this->do_type(); } + + // Set the index and section offset of this input file entry. + void + set_offset(unsigned int file_index, unsigned int offset) + { + this->file_index_ = file_index; + this->offset_ = offset; + } + + // Set the section offset of the supplemental information for this entry. + void + set_info_offset(unsigned int info_offset) + { this->info_offset_ = info_offset; } + + // Get the index of this input file entry. + unsigned int + get_file_index() const + { return this->file_index_; } + + // Get the section offset of this input file entry. + unsigned int + get_offset() const + { return this->offset_; } + + // Get the section offset of the supplemental information for this entry. + unsigned int + get_info_offset() const + { return this->info_offset_; } + + // Get the stringpool key for the input filename. + Stringpool::Key + get_filename_key() const + { return this->filename_key_; } + + // Get the serial number of the input file. + unsigned int + arg_serial() const + { return this->arg_serial_; } + + // Get the modification time of the input file. + const Timespec& + get_mtime() const + { return this->mtime_; } + + // Record that the file was found in a system directory. + void + set_is_in_system_directory() + { this->is_in_system_directory_ = true; } + + // Return TRUE if the file was found in a system directory. + bool + is_in_system_directory() const + { return this->is_in_system_directory_; } + + // Record that the file was linked with --as-needed. + void + set_as_needed() + { this->as_needed_ = true; } + + // Return TRUE if the file was linked with --as-needed. + bool + as_needed() const + { return this->as_needed_; } + + // Return a pointer to the derived Incremental_script_entry object. + // Return NULL for input entries that are not script files. + Incremental_script_entry* + script_entry() + { return this->do_script_entry(); } + + // Return a pointer to the derived Incremental_object_entry object. + // Return NULL for input entries that are not object files. + Incremental_object_entry* + object_entry() + { return this->do_object_entry(); } + + // Return a pointer to the derived Incremental_dynobj_entry object. + // Return NULL for input entries that are not shared object files. + Incremental_dynobj_entry* + dynobj_entry() + { return this->do_dynobj_entry(); } + + // Return a pointer to the derived Incremental_archive_entry object. + // Return NULL for input entries that are not archive files. + Incremental_archive_entry* + archive_entry() + { return this->do_archive_entry(); } + + protected: + // Return the type of input file. + virtual Incremental_input_type + do_type() const = 0; + + // Return a pointer to the derived Incremental_script_entry object. + // Return NULL for input entries that are not script files. + virtual Incremental_script_entry* + do_script_entry() + { return NULL; } + + // Return a pointer to the derived Incremental_object_entry object. + // Return NULL for input entries that are not object files. + virtual Incremental_object_entry* + do_object_entry() + { return NULL; } + + // Return a pointer to the derived Incremental_dynobj_entry object. + // Return NULL for input entries that are not shared object files. + virtual Incremental_dynobj_entry* + do_dynobj_entry() + { return NULL; } + + // Return a pointer to the derived Incremental_archive_entry object. + // Return NULL for input entries that are not archive files. + virtual Incremental_archive_entry* + do_archive_entry() + { return NULL; } + + private: + // Key of the filename string in the section stringtable. + Stringpool::Key filename_key_; + + // Index of the entry in the output section. + unsigned int file_index_; + + // Offset of the entry in the output section. + unsigned int offset_; + + // Offset of the extra information in the output section. + unsigned int info_offset_; + + // Serial number of the file in the argument list. + unsigned int arg_serial_; + + // Last modification time of the file. + Timespec mtime_; + + // TRUE if the file was found in a system directory. + bool is_in_system_directory_; + + // TRUE if the file was linked with --as-needed. + bool as_needed_; +}; + +// Information about a script input that will persist during the whole linker +// run. Needed only during an incremental build to retrieve the input files +// added by this script. + +class Script_info +{ + public: + Script_info(const std::string& filename) + : filename_(filename), input_file_index_(0), + incremental_script_entry_(NULL) + { } + + Script_info(const std::string& filename, unsigned int input_file_index) + : filename_(filename), input_file_index_(input_file_index), + incremental_script_entry_(NULL) + { } + + // Store a pointer to the incremental information for this script. + void + set_incremental_info(Incremental_script_entry* entry) + { this->incremental_script_entry_ = entry; } + + // Return the filename. + const std::string& + filename() const + { return this->filename_; } + + // Return the input file index. + unsigned int + input_file_index() const + { return this->input_file_index_; } + + // Return the pointer to the incremental information for this script. + Incremental_script_entry* + incremental_info() const + { return this->incremental_script_entry_; } + + private: + const std::string filename_; + unsigned int input_file_index_; + Incremental_script_entry* incremental_script_entry_; +}; + +// Class for recording input scripts. + +class Incremental_script_entry : public Incremental_input_entry +{ + public: + Incremental_script_entry(Stringpool::Key filename_key, + unsigned int arg_serial, Script_info* /*script*/, + Timespec mtime) + : Incremental_input_entry(filename_key, arg_serial, mtime), + objects_() + { } + + // Add a member object to the archive. + void + add_object(Incremental_input_entry* obj_entry) + { + this->objects_.push_back(obj_entry); + } + + // Return the number of objects included by this script. + unsigned int + get_object_count() + { return this->objects_.size(); } + + // Return the Nth object. + Incremental_input_entry* + get_object(unsigned int n) + { + gold_assert(n < this->objects_.size()); + return this->objects_[n]; + } + + protected: + virtual Incremental_input_type + do_type() const + { return INCREMENTAL_INPUT_SCRIPT; } + + // Return a pointer to the derived Incremental_script_entry object. + virtual Incremental_script_entry* + do_script_entry() + { return this; } + + private: + // Objects that have been included by this script. + std::vector objects_; +}; + +// Class for recording input object files. + +class Incremental_object_entry : public Incremental_input_entry +{ + public: + Incremental_object_entry(Stringpool::Key filename_key, Object* obj, + unsigned int arg_serial, Timespec mtime) + : Incremental_input_entry(filename_key, arg_serial, mtime), obj_(obj), + is_member_(false), sections_(), groups_() + { this->sections_.reserve(obj->shnum()); } + + // Get the object. + Object* + object() const + { return this->obj_; } + + // Record that this object is an archive member. + void + set_is_member() + { this->is_member_ = true; } + + // Return true if this object is an archive member. + bool + is_member() const + { return this->is_member_; } + + // Add an input section. + void + add_input_section(unsigned int shndx, Stringpool::Key name_key, off_t sh_size) + { this->sections_.push_back(Input_section(shndx, name_key, sh_size)); } + + // Return the number of input sections in this object. + unsigned int + get_input_section_count() const + { return this->sections_.size(); } + + // Return the input section index for the Nth input section. + Stringpool::Key + get_input_section_index(unsigned int n) const + { return this->sections_[n].shndx_; } + + // Return the stringpool key of the Nth input section. + Stringpool::Key + get_input_section_name_key(unsigned int n) const + { return this->sections_[n].name_key_; } + + // Return the size of the Nth input section. + off_t + get_input_section_size(unsigned int n) const + { return this->sections_[n].sh_size_; } + + // Add a kept COMDAT group. + void + add_comdat_group(Stringpool::Key signature_key) + { this->groups_.push_back(signature_key); } + + // Return the number of COMDAT groups. + unsigned int + get_comdat_group_count() const + { return this->groups_.size(); } + + // Return the stringpool key for the signature of the Nth comdat group. + Stringpool::Key + get_comdat_signature_key(unsigned int n) const + { return this->groups_[n]; } + + protected: + virtual Incremental_input_type + do_type() const + { + return (this->is_member_ + ? INCREMENTAL_INPUT_ARCHIVE_MEMBER + : INCREMENTAL_INPUT_OBJECT); + } + + // Return a pointer to the derived Incremental_object_entry object. + virtual Incremental_object_entry* + do_object_entry() + { return this; } + + private: + // The object file itself. + Object* obj_; + + // Whether this object is an archive member. + bool is_member_; + + // Input sections. + struct Input_section + { + Input_section(unsigned int shndx, Stringpool::Key name_key, off_t sh_size) + : shndx_(shndx), name_key_(name_key), sh_size_(sh_size) + { } + unsigned int shndx_; + Stringpool::Key name_key_; + off_t sh_size_; + }; + std::vector sections_; + + // COMDAT groups. + std::vector groups_; +}; + +// Class for recording shared library input files. + +class Incremental_dynobj_entry : public Incremental_input_entry +{ + public: + Incremental_dynobj_entry(Stringpool::Key filename_key, + Stringpool::Key soname_key, Object* obj, + unsigned int arg_serial, Timespec mtime) + : Incremental_input_entry(filename_key, arg_serial, mtime), + soname_key_(soname_key), obj_(obj) + { } + + // Get the object. + Object* + object() const + { return this->obj_; } + + // Get the stringpool key for the soname. + Stringpool::Key + get_soname_key() const + { return this->soname_key_; } + + protected: + virtual Incremental_input_type + do_type() const + { return INCREMENTAL_INPUT_SHARED_LIBRARY; } + + // Return a pointer to the derived Incremental_dynobj_entry object. + virtual Incremental_dynobj_entry* + do_dynobj_entry() + { return this; } + + private: + // Key of the soname string in the section stringtable. + Stringpool::Key soname_key_; + + // The object file itself. + Object* obj_; +}; + +// Class for recording archive library input files. + +class Incremental_archive_entry : public Incremental_input_entry +{ + public: + Incremental_archive_entry(Stringpool::Key filename_key, + unsigned int arg_serial, Timespec mtime) + : Incremental_input_entry(filename_key, arg_serial, mtime), members_(), + unused_syms_() + { } + + // Add a member object to the archive. + void + add_object(Incremental_object_entry* obj_entry) + { + this->members_.push_back(obj_entry); + obj_entry->set_is_member(); + } + + // Add an unused global symbol to the archive. + void + add_unused_global_symbol(Stringpool::Key symbol_key) + { this->unused_syms_.push_back(symbol_key); } + + // Return the number of member objects included in the link. + unsigned int + get_member_count() + { return this->members_.size(); } + + // Return the Nth member object. + Incremental_object_entry* + get_member(unsigned int n) + { return this->members_[n]; } + + // Return the number of unused global symbols in this archive. + unsigned int + get_unused_global_symbol_count() + { return this->unused_syms_.size(); } + + // Return the Nth unused global symbol. + Stringpool::Key + get_unused_global_symbol(unsigned int n) + { return this->unused_syms_[n]; } + + protected: + virtual Incremental_input_type + do_type() const + { return INCREMENTAL_INPUT_ARCHIVE; } + + // Return a pointer to the derived Incremental_archive_entry object. + virtual Incremental_archive_entry* + do_archive_entry() + { return this; } + + private: + // Members of the archive that have been included in the link. + std::vector members_; + + // Unused global symbols from this archive. + std::vector unused_syms_; +}; + +// This class contains the information needed during an incremental +// build about the inputs necessary to build the .gnu_incremental_inputs. + +class Incremental_inputs +{ + public: + typedef std::vector Input_list; + + Incremental_inputs() + : inputs_(), command_line_(), command_line_key_(0), + strtab_(new Stringpool()), current_object_(NULL), + current_object_entry_(NULL), inputs_section_(NULL), + symtab_section_(NULL), relocs_section_(NULL), + reloc_count_(0) + { } + + ~Incremental_inputs() { delete this->strtab_; } + + // Record the command line. + void + report_command_line(int argc, const char* const* argv); + + // Record the initial info for archive file ARCHIVE. + void + report_archive_begin(Library_base* arch, unsigned int arg_serial, + Script_info* script_info); + + // Record the final info for archive file ARCHIVE. + void + report_archive_end(Library_base* arch); + + // Record the info for object file OBJ. If ARCH is not NULL, + // attach the object file to the archive. + void + report_object(Object* obj, unsigned int arg_serial, Library_base* arch, + Script_info* script_info); + + // Record an input section belonging to object file OBJ. + void + report_input_section(Object* obj, unsigned int shndx, const char* name, + off_t sh_size); + + // Record a kept COMDAT group belonging to object file OBJ. + void + report_comdat_group(Object* obj, const char* name); + + // Record the info for input script SCRIPT. + void + report_script(Script_info* script, unsigned int arg_serial, + Timespec mtime); + + // Return the running count of incremental relocations. + unsigned int + get_reloc_count() const + { return this->reloc_count_; } + + // Update the running count of incremental relocations. + void + set_reloc_count(unsigned int count) + { this->reloc_count_ = count; } + + // Prepare for layout. Called from Layout::finalize. + void + finalize(); + + // Create the .gnu_incremental_inputs and related sections. + void + create_data_sections(Symbol_table* symtab); + + // Return the .gnu_incremental_inputs section. + Output_section_data* + inputs_section() const + { return this->inputs_section_; } + + // Return the .gnu_incremental_symtab section. + Output_data_space* + symtab_section() const + { return this->symtab_section_; } + + // Return the .gnu_incremental_relocs section. + Output_data_space* + relocs_section() const + { return this->relocs_section_; } + + // Return the .gnu_incremental_got_plt section. + Output_data_space* + got_plt_section() const + { return this->got_plt_section_; } + + // Return the .gnu_incremental_strtab stringpool. + Stringpool* + get_stringpool() const + { return this->strtab_; } + + // Return the canonical form of the command line, as will be stored in + // .gnu_incremental_strtab. + const std::string& + command_line() const + { return this->command_line_; } + + // Return the stringpool key of the command line. + Stringpool::Key + command_line_key() const + { return this->command_line_key_; } + + // Return the number of input files. + int + input_file_count() const + { return this->inputs_.size(); } + + // Return the input files. + const Input_list& + input_files() const + { return this->inputs_; } + + // Return the sh_entsize value for the .gnu_incremental_relocs section. + unsigned int + relocs_entsize() const; + + private: + // The list of input files. + Input_list inputs_; + + // Canonical form of the command line, as will be stored in + // .gnu_incremental_strtab. + std::string command_line_; + + // The key of the command line string in the string pool. + Stringpool::Key command_line_key_; + + // The .gnu_incremental_strtab string pool associated with the + // .gnu_incremental_inputs. + Stringpool* strtab_; + + // Keep track of the object currently being processed. + Object* current_object_; + Incremental_object_entry* current_object_entry_; + + // The .gnu_incremental_inputs section. + Output_section_data* inputs_section_; + + // The .gnu_incremental_symtab section. + Output_data_space* symtab_section_; + + // The .gnu_incremental_relocs section. + Output_data_space* relocs_section_; + + // The .gnu_incremental_got_plt section. + Output_data_space* got_plt_section_; + + // Total count of incremental relocations. Updated during Scan_relocs + // phase at the completion of each object file. + unsigned int reloc_count_; +}; + +// Reader class for global symbol info from an object file entry in +// the .gnu_incremental_inputs section. + +template +class Incremental_global_symbol_reader +{ + private: + typedef elfcpp::Swap<32, big_endian> Swap32; + + public: + Incremental_global_symbol_reader(const unsigned char* p) + : p_(p) + { } + + unsigned int + output_symndx() const + { return Swap32::readval(this->p_); } + + unsigned int + shndx() const + { return Swap32::readval(this->p_ + 4); } + + unsigned int + next_offset() const + { return Swap32::readval(this->p_ + 8); } + + unsigned int + reloc_count() const + { return Swap32::readval(this->p_ + 12); } + + unsigned int + reloc_offset() const + { return Swap32::readval(this->p_ + 16); } + + private: + // Base address of the symbol entry. + const unsigned char* p_; +}; + +// Reader class for .gnu_incremental_inputs section. + +template +class Incremental_inputs_reader +{ + private: + typedef elfcpp::Swap Swap; + typedef elfcpp::Swap<16, big_endian> Swap16; + typedef elfcpp::Swap<32, big_endian> Swap32; + typedef elfcpp::Swap<64, big_endian> Swap64; + + public: + // Size of the .gnu_incremental_inputs header. + // (3 x 4-byte fields, plus 4 bytes padding.) + static const unsigned int header_size = 16; + // Size of an input file entry. + // (2 x 4-byte fields, 1 x 12-byte field, 2 x 2-byte fields.) + static const unsigned int input_entry_size = 24; + // Size of the first part of the supplemental info block for + // relocatable objects and archive members. + // (7 x 4-byte fields, plus 4 bytes padding.) + static const unsigned int object_info_size = 32; + // Size of an input section entry. + // (2 x 4-byte fields, 2 x address-sized fields.) + static const unsigned int input_section_entry_size = 8 + 2 * size / 8; + // Size of a global symbol entry in the supplemental info block. + // (5 x 4-byte fields.) + static const unsigned int global_sym_entry_size = 20; + + Incremental_inputs_reader() + : p_(NULL), strtab_(NULL, 0), input_file_count_(0) + { } + + Incremental_inputs_reader(const unsigned char* p, + const elfcpp::Elf_strtab& strtab) + : p_(p), strtab_(strtab) + { this->input_file_count_ = Swap32::readval(this->p_ + 4); } + + // Return the version number. + unsigned int + version() const + { return Swap32::readval(this->p_); } + + // Return the count of input file entries. + unsigned int + input_file_count() const + { return this->input_file_count_; } + + // Return the command line. + const char* + command_line() const + { + unsigned int offset = Swap32::readval(this->p_ + 8); + return this->get_string(offset); + } + + // Reader class for an input file entry and its supplemental info. + class Incremental_input_entry_reader + { + private: + static const unsigned int object_info_size = + Incremental_inputs_reader::object_info_size; + static const unsigned int input_section_entry_size = + Incremental_inputs_reader::input_section_entry_size; + static const unsigned int global_sym_entry_size = + Incremental_inputs_reader::global_sym_entry_size; + + public: + Incremental_input_entry_reader(const Incremental_inputs_reader* inputs, + unsigned int offset) + : inputs_(inputs), offset_(offset) + { + this->info_offset_ = Swap32::readval(inputs->p_ + offset + 4); + this->flags_ = Swap16::readval(this->inputs_->p_ + offset + 20); + } + + // Return the filename. + const char* + filename() const + { + unsigned int offset = Swap32::readval(this->inputs_->p_ + this->offset_); + return this->inputs_->get_string(offset); + } + + // Return the argument serial number. + unsigned int + arg_serial() const + { + return Swap16::readval(this->inputs_->p_ + this->offset_ + 22); + } + + // Return the timestamp. + Timespec + get_mtime() const + { + Timespec t; + const unsigned char* p = this->inputs_->p_ + this->offset_ + 8; + t.seconds = Swap64::readval(p); + t.nanoseconds = Swap32::readval(p+8); + return t; + } + + // Return the type of input file. + Incremental_input_type + type() const + { return static_cast(this->flags_ & 0xff); } + + // Return TRUE if the file was found in a system directory. + bool + is_in_system_directory() const + { return (this->flags_ & INCREMENTAL_INPUT_IN_SYSTEM_DIR) != 0; } + + // Return TRUE if the file was linked with --as-needed. + bool + as_needed() const + { return (this->flags_ & INCREMENTAL_INPUT_AS_NEEDED) != 0; } + + // Return the input section count -- for objects only. + unsigned int + get_input_section_count() const + { + gold_assert(this->type() == INCREMENTAL_INPUT_OBJECT + || this->type() == INCREMENTAL_INPUT_ARCHIVE_MEMBER); + return Swap32::readval(this->inputs_->p_ + this->info_offset_); + } + + // Return the soname -- for shared libraries only. + const char* + get_soname() const + { + gold_assert(this->type() == INCREMENTAL_INPUT_SHARED_LIBRARY); + unsigned int offset = Swap32::readval(this->inputs_->p_ + + this->info_offset_); + return this->inputs_->get_string(offset); + } + + // Return the offset of the supplemental info for symbol SYMNDX -- + // for objects only. + unsigned int + get_symbol_offset(unsigned int symndx) const + { + gold_assert(this->type() == INCREMENTAL_INPUT_OBJECT + || this->type() == INCREMENTAL_INPUT_ARCHIVE_MEMBER); + + unsigned int section_count = this->get_input_section_count(); + return (this->info_offset_ + + this->object_info_size + + section_count * this->input_section_entry_size + + symndx * this->global_sym_entry_size); + } + + // Return the global symbol count -- for objects & shared libraries only. + unsigned int + get_global_symbol_count() const + { + gold_assert(this->type() == INCREMENTAL_INPUT_OBJECT + || this->type() == INCREMENTAL_INPUT_ARCHIVE_MEMBER + || this->type() == INCREMENTAL_INPUT_SHARED_LIBRARY); + return Swap32::readval(this->inputs_->p_ + this->info_offset_ + 4); + } + + // Return the offset of the first local symbol -- for objects only. + unsigned int + get_local_symbol_offset() const + { + gold_assert(this->type() == INCREMENTAL_INPUT_OBJECT + || this->type() == INCREMENTAL_INPUT_ARCHIVE_MEMBER); + + return Swap32::readval(this->inputs_->p_ + this->info_offset_ + 8); + } + + // Return the local symbol count -- for objects only. + unsigned int + get_local_symbol_count() const + { + gold_assert(this->type() == INCREMENTAL_INPUT_OBJECT + || this->type() == INCREMENTAL_INPUT_ARCHIVE_MEMBER); + + return Swap32::readval(this->inputs_->p_ + this->info_offset_ + 12); + } + + // Return the index of the first dynamic relocation -- for objects only. + unsigned int + get_first_dyn_reloc() const + { + gold_assert(this->type() == INCREMENTAL_INPUT_OBJECT + || this->type() == INCREMENTAL_INPUT_ARCHIVE_MEMBER); + + return Swap32::readval(this->inputs_->p_ + this->info_offset_ + 16); + } + + // Return the dynamic relocation count -- for objects only. + unsigned int + get_dyn_reloc_count() const + { + gold_assert(this->type() == INCREMENTAL_INPUT_OBJECT + || this->type() == INCREMENTAL_INPUT_ARCHIVE_MEMBER); + + return Swap32::readval(this->inputs_->p_ + this->info_offset_ + 20); + } + + // Return the COMDAT group count -- for objects only. + unsigned int + get_comdat_group_count() const + { + gold_assert(this->type() == INCREMENTAL_INPUT_OBJECT + || this->type() == INCREMENTAL_INPUT_ARCHIVE_MEMBER); + + return Swap32::readval(this->inputs_->p_ + this->info_offset_ + 24); + } + + // Return the object count -- for scripts only. + unsigned int + get_object_count() const + { + gold_assert(this->type() == INCREMENTAL_INPUT_SCRIPT); + return Swap32::readval(this->inputs_->p_ + this->info_offset_); + } + + // Return the input file offset for object N -- for scripts only. + unsigned int + get_object_offset(unsigned int n) const + { + gold_assert(this->type() == INCREMENTAL_INPUT_SCRIPT); + return Swap32::readval(this->inputs_->p_ + this->info_offset_ + + 4 + n * 4); + } + + // Return the member count -- for archives only. + unsigned int + get_member_count() const + { + gold_assert(this->type() == INCREMENTAL_INPUT_ARCHIVE); + return Swap32::readval(this->inputs_->p_ + this->info_offset_); + } + + // Return the unused symbol count -- for archives only. + unsigned int + get_unused_symbol_count() const + { + gold_assert(this->type() == INCREMENTAL_INPUT_ARCHIVE); + return Swap32::readval(this->inputs_->p_ + this->info_offset_ + 4); + } + + // Return the input file offset for archive member N -- for archives only. + unsigned int + get_member_offset(unsigned int n) const + { + gold_assert(this->type() == INCREMENTAL_INPUT_ARCHIVE); + return Swap32::readval(this->inputs_->p_ + this->info_offset_ + + 8 + n * 4); + } + + // Return the Nth unused global symbol -- for archives only. + const char* + get_unused_symbol(unsigned int n) const + { + gold_assert(this->type() == INCREMENTAL_INPUT_ARCHIVE); + unsigned int member_count = this->get_member_count(); + unsigned int offset = Swap32::readval(this->inputs_->p_ + + this->info_offset_ + 8 + + member_count * 4 + + n * 4); + return this->inputs_->get_string(offset); + } + + // Information about an input section. + struct Input_section_info + { + const char* name; + unsigned int output_shndx; + off_t sh_offset; + off_t sh_size; + }; + + // Return info about the Nth input section -- for objects only. + Input_section_info + get_input_section(unsigned int n) const + { + Input_section_info info; + const unsigned char* p = (this->inputs_->p_ + + this->info_offset_ + + this->object_info_size + + n * this->input_section_entry_size); + unsigned int name_offset = Swap32::readval(p); + info.name = this->inputs_->get_string(name_offset); + info.output_shndx = Swap32::readval(p + 4); + info.sh_offset = Swap::readval(p + 8); + info.sh_size = Swap::readval(p + 8 + size / 8); + return info; + } + + // Return info about the Nth global symbol -- for objects only. + Incremental_global_symbol_reader + get_global_symbol_reader(unsigned int n) const + { + gold_assert(this->type() == INCREMENTAL_INPUT_OBJECT + || this->type() == INCREMENTAL_INPUT_ARCHIVE_MEMBER); + unsigned int section_count = this->get_input_section_count(); + const unsigned char* p = (this->inputs_->p_ + + this->info_offset_ + + this->object_info_size + + section_count * this->input_section_entry_size + + n * this->global_sym_entry_size); + return Incremental_global_symbol_reader(p); + } + + // Return the signature of the Nth comdat group -- for objects only. + const char* + get_comdat_group_signature(unsigned int n) const + { + unsigned int section_count = this->get_input_section_count(); + unsigned int symbol_count = this->get_global_symbol_count(); + const unsigned char* p = (this->inputs_->p_ + + this->info_offset_ + + this->object_info_size + + section_count * this->input_section_entry_size + + symbol_count * this->global_sym_entry_size + + n * 4); + unsigned int name_offset = Swap32::readval(p); + return this->inputs_->get_string(name_offset); + } + + // Return the output symbol index for the Nth global symbol -- for shared + // libraries only. Sets *IS_DEF to TRUE if the symbol is defined in this + // input file. Sets *IS_COPY to TRUE if the symbol was copied from this + // input file with a COPY relocation. + unsigned int + get_output_symbol_index(unsigned int n, bool* is_def, bool* is_copy) + { + gold_assert(this->type() == INCREMENTAL_INPUT_SHARED_LIBRARY); + const unsigned char* p = (this->inputs_->p_ + + this->info_offset_ + 8 + + n * 4); + unsigned int output_symndx = Swap32::readval(p); + unsigned int flags = output_symndx >> INCREMENTAL_SHLIB_SYM_FLAGS_SHIFT; + output_symndx &= ((1U << INCREMENTAL_SHLIB_SYM_FLAGS_SHIFT) - 1); + switch (flags) + { + case INCREMENTAL_SHLIB_SYM_DEF: + *is_def = true; + *is_copy = false; + break; + case INCREMENTAL_SHLIB_SYM_COPY: + *is_def = true; + *is_copy = true; + break; + default: + *is_def = false; + *is_copy = false; + } + return output_symndx; + } + + private: + // The reader instance for the containing section. + const Incremental_inputs_reader* inputs_; + // The flags, including the type of input file. + unsigned int flags_; + // Section offset to the input file entry. + unsigned int offset_; + // Section offset to the supplemental info for the input file. + unsigned int info_offset_; + }; + + // Return the offset of an input file entry given its index N. + unsigned int + input_file_offset(unsigned int n) const + { + gold_assert(n < this->input_file_count_); + return this->header_size + n * this->input_entry_size; + } + + // Return the index of an input file entry given its OFFSET. + unsigned int + input_file_index(unsigned int offset) const + { + int n = ((offset - this->header_size) / this->input_entry_size); + gold_assert(input_file_offset(n) == offset); + return n; + } + + // Return a reader for the Nth input file entry. + Incremental_input_entry_reader + input_file(unsigned int n) const + { return Incremental_input_entry_reader(this, this->input_file_offset(n)); } + + // Return a reader for the input file entry at OFFSET. + Incremental_input_entry_reader + input_file_at_offset(unsigned int offset) const + { + gold_assert(offset < (this->header_size + + this->input_file_count_ * this->input_entry_size)); + return Incremental_input_entry_reader(this, offset); + } + + // Return a reader for the global symbol info at OFFSET. + Incremental_global_symbol_reader + global_symbol_reader_at_offset(unsigned int offset) const + { + const unsigned char* p = this->p_ + offset; + return Incremental_global_symbol_reader(p); + } + + private: + // Lookup a string in the ELF string table. + const char* get_string(unsigned int offset) const + { + const char* s; + if (this->strtab_.get_c_string(offset, &s)) + return s; + return NULL; + } + + // Base address of the .gnu_incremental_inputs section. + const unsigned char* p_; + // The associated ELF string table. + elfcpp::Elf_strtab strtab_; + // The number of input file entries in this section. + unsigned int input_file_count_; +}; + +// Reader class for the .gnu_incremental_symtab section. + +template +class Incremental_symtab_reader +{ + public: + Incremental_symtab_reader() + : p_(NULL), len_(0) + { } + + Incremental_symtab_reader(const unsigned char* p, off_t len) + : p_(p), len_(len) + { } + + // Return the count of symbols in this section. + unsigned int + symbol_count() const + { return static_cast(this->len_ / 4); } + + // Return the list head for symbol table entry N. + unsigned int + get_list_head(unsigned int n) const + { return elfcpp::Swap<32, big_endian>::readval(this->p_ + 4 * n); } + + private: + // Base address of the .gnu_incremental_relocs section. + const unsigned char* p_; + // Size of the section. + off_t len_; +}; + +// Reader class for the .gnu_incremental_relocs section. + +template +class Incremental_relocs_reader +{ + private: + // Size of each field. + static const unsigned int field_size = size / 8; + + public: + typedef typename elfcpp::Elf_types::Elf_Addr Address; + typedef typename elfcpp::Elf_types::Elf_Swxword Addend; + + // Size of each entry. + static const unsigned int reloc_size = 8 + 2 * field_size; + + Incremental_relocs_reader() + : p_(NULL), len_(0) + { } + + Incremental_relocs_reader(const unsigned char* p, off_t len) + : p_(p), len_(len) + { } + + // Return the count of relocations in this section. + unsigned int + reloc_count() const + { return static_cast(this->len_ / reloc_size); } + + // Return the relocation type for relocation entry at offset OFF. + unsigned int + get_r_type(unsigned int off) const + { return elfcpp::Swap<32, big_endian>::readval(this->p_ + off); } + + // Return the output section index for relocation entry at offset OFF. + unsigned int + get_r_shndx(unsigned int off) const + { return elfcpp::Swap<32, big_endian>::readval(this->p_ + off + 4); } + + // Return the output section offset for relocation entry at offset OFF. + Address + get_r_offset(unsigned int off) const + { return elfcpp::Swap::readval(this->p_ + off + 8); } + + // Return the addend for relocation entry at offset OFF. + Addend + get_r_addend(unsigned int off) const + { + return elfcpp::Swap::readval(this->p_ + off + 8 + + this->field_size); + } + + // Return a pointer to the relocation entry at offset OFF. + const unsigned char* + data(unsigned int off) const + { return this->p_ + off; } + + private: + // Base address of the .gnu_incremental_relocs section. + const unsigned char* p_; + // Size of the section. + off_t len_; +}; + +// Reader class for the .gnu_incremental_got_plt section. + +template +class Incremental_got_plt_reader +{ + public: + Incremental_got_plt_reader() + : p_(NULL), got_count_(0), got_desc_p_(NULL), plt_desc_p_(NULL) + { } + + Incremental_got_plt_reader(const unsigned char* p) : p_(p) + { + this->got_count_ = elfcpp::Swap<32, big_endian>::readval(p); + this->got_desc_p_ = p + 8 + ((this->got_count_ + 3) & ~3); + this->plt_desc_p_ = this->got_desc_p_ + this->got_count_ * 8; + } + + // Return the GOT entry count. + unsigned int + get_got_entry_count() const + { + return this->got_count_; + } + + // Return the PLT entry count. + unsigned int + get_plt_entry_count() const + { + return elfcpp::Swap<32, big_endian>::readval(this->p_ + 4); + } + + // Return the GOT type for GOT entry N. + unsigned int + get_got_type(unsigned int n) + { + return this->p_[8 + n]; + } + + // Return the symbol index for GOT entry N. + unsigned int + get_got_symndx(unsigned int n) + { + return elfcpp::Swap<32, big_endian>::readval(this->got_desc_p_ + n * 8); + } + + // Return the input file index for GOT entry N. + unsigned int + get_got_input_index(unsigned int n) + { + return elfcpp::Swap<32, big_endian>::readval(this->got_desc_p_ + n * 8 + 4); + } + + // Return the PLT descriptor for PLT entry N. + unsigned int + get_plt_desc(unsigned int n) + { + return elfcpp::Swap<32, big_endian>::readval(this->plt_desc_p_ + n * 4); + } + + private: + // Base address of the .gnu_incremental_got_plt section. + const unsigned char* p_; + // GOT entry count. + unsigned int got_count_; + // Base address of the GOT descriptor array. + const unsigned char* got_desc_p_; + // Base address of the PLT descriptor array. + const unsigned char* plt_desc_p_; +}; + +// An object representing the ELF file we edit during an incremental build. +// Similar to Object or Dynobj, but operates on Output_file and contains +// methods to support incremental updating. This is the abstract parent class +// implemented in Sized_incremental_binary for a specific +// endianness and size. + +class Incremental_binary +{ + public: + Incremental_binary(Output_file* output, Target* /*target*/) + : input_args_map_(), library_map_(), script_map_(), + output_(output) + { } + + virtual + ~Incremental_binary() + { } + + // Check the .gnu_incremental_inputs section to see whether an incremental + // build is possible. + bool + check_inputs(const Command_line& cmdline, + Incremental_inputs* incremental_inputs) + { return this->do_check_inputs(cmdline, incremental_inputs); } + + // Report an error. + void + error(const char* format, ...) const ATTRIBUTE_PRINTF_2; + + // Proxy class for a sized Incremental_input_entry_reader. + + class Input_reader + { + public: + Input_reader() + { } + + virtual + ~Input_reader() + { } + + const char* + filename() const + { return this->do_filename(); } + + Timespec + get_mtime() const + { return this->do_get_mtime(); } + + Incremental_input_type + type() const + { return this->do_type(); } + + unsigned int + arg_serial() const + { return this->do_arg_serial(); } + + unsigned int + get_unused_symbol_count() const + { return this->do_get_unused_symbol_count(); } + + const char* + get_unused_symbol(unsigned int n) const + { return this->do_get_unused_symbol(n); } + + protected: + virtual const char* + do_filename() const = 0; + + virtual Timespec + do_get_mtime() const = 0; + + virtual Incremental_input_type + do_type() const = 0; + + virtual unsigned int + do_arg_serial() const = 0; + + virtual unsigned int + do_get_unused_symbol_count() const = 0; + + virtual const char* + do_get_unused_symbol(unsigned int n) const = 0; + }; + + // Return the number of input files. + unsigned int + input_file_count() const + { return this->do_input_file_count(); } + + // Return an Input_reader for input file N. + const Input_reader* + get_input_reader(unsigned int n) const + { return this->do_get_input_reader(n); } + + // Return TRUE if the input file N has changed since the last link. + bool + file_has_changed(unsigned int n) const + { return this->do_file_has_changed(n); } + + // Return the Input_argument for input file N. Returns NULL if + // the Input_argument is not available. + const Input_argument* + get_input_argument(unsigned int n) const + { + const Input_reader* input_file = this->do_get_input_reader(n); + unsigned int arg_serial = input_file->arg_serial(); + if (arg_serial == 0 || arg_serial > this->input_args_map_.size()) + return NULL; + return this->input_args_map_[arg_serial - 1]; + } + + // Return an Incremental_library for the given input file. + Incremental_library* + get_library(unsigned int n) const + { return this->library_map_[n]; } + + // Return a Script_info for the given input file. + Script_info* + get_script_info(unsigned int n) const + { return this->script_map_[n]; } + + // Initialize the layout of the output file based on the existing + // output file. + void + init_layout(Layout* layout) + { this->do_init_layout(layout); } + + // Mark regions of the input file that must be kept unchanged. + void + reserve_layout(unsigned int input_file_index) + { this->do_reserve_layout(input_file_index); } + + // Process the GOT and PLT entries from the existing output file. + void + process_got_plt(Symbol_table* symtab, Layout* layout) + { this->do_process_got_plt(symtab, layout); } + + // Emit COPY relocations from the existing output file. + void + emit_copy_relocs(Symbol_table* symtab) + { this->do_emit_copy_relocs(symtab); } + + // Apply incremental relocations for symbols whose values have changed. + void + apply_incremental_relocs(const Symbol_table* symtab, Layout* layout, + Output_file* of) + { this->do_apply_incremental_relocs(symtab, layout, of); } + + // Functions and types for the elfcpp::Elf_file interface. This + // permit us to use Incremental_binary as the File template parameter for + // elfcpp::Elf_file. + + // The View class is returned by view. It must support a single + // method, data(). This is trivial, because Output_file::get_output_view + // does what we need. + class View + { + public: + View(const unsigned char* p) + : p_(p) + { } + + const unsigned char* + data() const + { return this->p_; } + + private: + const unsigned char* p_; + }; + + // Return a View. + View + view(off_t file_offset, section_size_type data_size) + { return View(this->output_->get_input_view(file_offset, data_size)); } + + // A location in the file. + struct Location + { + off_t file_offset; + off_t data_size; + + Location(off_t fo, section_size_type ds) + : file_offset(fo), data_size(ds) + { } + + Location() + : file_offset(0), data_size(0) + { } + }; + + // Get a View given a Location. + View + view(Location loc) + { return View(this->view(loc.file_offset, loc.data_size)); } + + // Return the Output_file. + Output_file* + output_file() + { return this->output_; } + + protected: + // Check the .gnu_incremental_inputs section to see whether an incremental + // build is possible. + virtual bool + do_check_inputs(const Command_line& cmdline, + Incremental_inputs* incremental_inputs) = 0; + + // Return TRUE if input file N has changed since the last incremental link. + virtual bool + do_file_has_changed(unsigned int n) const = 0; + + // Initialize the layout of the output file based on the existing + // output file. + virtual void + do_init_layout(Layout* layout) = 0; + + // Mark regions of the input file that must be kept unchanged. + virtual void + do_reserve_layout(unsigned int input_file_index) = 0; + + // Process the GOT and PLT entries from the existing output file. + virtual void + do_process_got_plt(Symbol_table* symtab, Layout* layout) = 0; + + // Emit COPY relocations from the existing output file. + virtual void + do_emit_copy_relocs(Symbol_table* symtab) = 0; + + // Apply incremental relocations for symbols whose values have changed. + virtual void + do_apply_incremental_relocs(const Symbol_table*, Layout*, Output_file*) = 0; + + virtual unsigned int + do_input_file_count() const = 0; + + virtual const Input_reader* + do_get_input_reader(unsigned int) const = 0; + + // Map from input file index to Input_argument. + std::vector input_args_map_; + // Map from an input file index to an Incremental_library. + std::vector library_map_; + // Map from an input file index to a Script_info. + std::vector script_map_; + + private: + // Edited output file object. + Output_file* output_; +}; + +template +class Sized_relobj_incr; + +template +class Sized_incremental_binary : public Incremental_binary +{ + public: + Sized_incremental_binary(Output_file* output, + const elfcpp::Ehdr& ehdr, + Target* target) + : Incremental_binary(output, target), elf_file_(this, ehdr), + input_objects_(), section_map_(), symbol_map_(), copy_relocs_(), + main_symtab_loc_(), main_strtab_loc_(), has_incremental_info_(false), + inputs_reader_(), symtab_reader_(), relocs_reader_(), got_plt_reader_(), + input_entry_readers_() + { this->setup_readers(); } + + // Returns TRUE if the file contains incremental info. + bool + has_incremental_info() const + { return this->has_incremental_info_; } + + // Record a pointer to the object for input file N. + void + set_input_object(unsigned int n, + Sized_relobj_incr* obj) + { this->input_objects_[n] = obj; } + + // Return a pointer to the object for input file N. + Sized_relobj_incr* + input_object(unsigned int n) const + { + gold_assert(n < this->input_objects_.size()); + return this->input_objects_[n]; + } + + // Return the Output_section for section index SHNDX. + Output_section* + output_section(unsigned int shndx) + { return this->section_map_[shndx]; } + + // Map a symbol table entry from the base file to the output symbol table. + // SYMNDX is relative to the first forced-local or global symbol in the + // input file symbol table. + void + add_global_symbol(unsigned int symndx, Symbol* gsym) + { this->symbol_map_[symndx] = gsym; } + + // Map a symbol table entry from the base file to the output symbol table. + // SYMNDX is relative to the first forced-local or global symbol in the + // input file symbol table. + Symbol* + global_symbol(unsigned int symndx) const + { return this->symbol_map_[symndx]; } + + // Add a COPY relocation for a global symbol. + void + add_copy_reloc(Symbol* gsym, Output_section* os, off_t offset) + { this->copy_relocs_.push_back(Copy_reloc(gsym, os, offset)); } + + // Readers for the incremental info sections. + + const Incremental_inputs_reader& + inputs_reader() const + { return this->inputs_reader_; } + + const Incremental_symtab_reader& + symtab_reader() const + { return this->symtab_reader_; } + + const Incremental_relocs_reader& + relocs_reader() const + { return this->relocs_reader_; } + + const Incremental_got_plt_reader& + got_plt_reader() const + { return this->got_plt_reader_; } + + void + get_symtab_view(View* symtab_view, unsigned int* sym_count, + elfcpp::Elf_strtab* strtab); + + protected: + typedef Incremental_inputs_reader Inputs_reader; + typedef typename Inputs_reader::Incremental_input_entry_reader + Input_entry_reader; + + virtual bool + do_check_inputs(const Command_line& cmdline, + Incremental_inputs* incremental_inputs); + + // Return TRUE if input file N has changed since the last incremental link. + virtual bool + do_file_has_changed(unsigned int n) const; + + // Initialize the layout of the output file based on the existing + // output file. + virtual void + do_init_layout(Layout* layout); + + // Mark regions of the input file that must be kept unchanged. + virtual void + do_reserve_layout(unsigned int input_file_index); + + // Process the GOT and PLT entries from the existing output file. + virtual void + do_process_got_plt(Symbol_table* symtab, Layout* layout); + + // Emit COPY relocations from the existing output file. + virtual void + do_emit_copy_relocs(Symbol_table* symtab); + + // Apply incremental relocations for symbols whose values have changed. + virtual void + do_apply_incremental_relocs(const Symbol_table* symtab, Layout* layout, + Output_file* of); + + // Proxy class for a sized Incremental_input_entry_reader. + + class Sized_input_reader : public Input_reader + { + public: + Sized_input_reader(Input_entry_reader r) + : Input_reader(), reader_(r) + { } + + virtual + ~Sized_input_reader() + { } + + private: + const char* + do_filename() const + { return this->reader_.filename(); } + + Timespec + do_get_mtime() const + { return this->reader_.get_mtime(); } + + Incremental_input_type + do_type() const + { return this->reader_.type(); } + + unsigned int + do_arg_serial() const + { return this->reader_.arg_serial(); } + + unsigned int + do_get_unused_symbol_count() const + { return this->reader_.get_unused_symbol_count(); } + + const char* + do_get_unused_symbol(unsigned int n) const + { return this->reader_.get_unused_symbol(n); } + + Input_entry_reader reader_; + }; + + virtual unsigned int + do_input_file_count() const + { return this->inputs_reader_.input_file_count(); } + + virtual const Input_reader* + do_get_input_reader(unsigned int n) const + { + gold_assert(n < this->input_entry_readers_.size()); + return &this->input_entry_readers_[n]; + } + + private: + // List of symbols that need COPY relocations. + struct Copy_reloc + { + Copy_reloc(Symbol* sym, Output_section* os, off_t off) + : symbol(sym), output_section(os), offset(off) + { } + + // The global symbol to copy. + Symbol* symbol; + // The output section into which the symbol was copied. + Output_section* output_section; + // The offset within that output section. + off_t offset; + }; + typedef std::vector Copy_relocs; + + bool + find_incremental_inputs_sections(unsigned int* p_inputs_shndx, + unsigned int* p_symtab_shndx, + unsigned int* p_relocs_shndx, + unsigned int* p_got_plt_shndx, + unsigned int* p_strtab_shndx); + + void + setup_readers(); + + // Output as an ELF file. + elfcpp::Elf_file elf_file_; + + // Vector of pointers to the input objects for the unchanged files. + // For replaced files, the corresponding pointer is NULL. + std::vector*> input_objects_; + + // Map section index to an Output_section in the updated layout. + std::vector section_map_; + + // Map global symbols from the input file to the symbol table. + std::vector symbol_map_; + + // List of symbols that need COPY relocations. + Copy_relocs copy_relocs_; + + // Locations of the main symbol table and symbol string table. + Location main_symtab_loc_; + Location main_strtab_loc_; + + // Readers for the incremental info sections. + bool has_incremental_info_; + Incremental_inputs_reader inputs_reader_; + Incremental_symtab_reader symtab_reader_; + Incremental_relocs_reader relocs_reader_; + Incremental_got_plt_reader got_plt_reader_; + std::vector input_entry_readers_; +}; + +// An incremental Relobj. This class represents a relocatable object +// that has not changed since the last incremental link, and whose contents +// can be used directly from the base file. + +template +class Sized_relobj_incr : public Sized_relobj +{ + public: + typedef typename elfcpp::Elf_types::Elf_Addr Address; + typedef typename Sized_relobj::Symbols Symbols; + + Sized_relobj_incr(const std::string& name, + Sized_incremental_binary* ibase, + unsigned int input_file_index); + + private: + // For convenience. + typedef Sized_relobj_incr This; + static const int sym_size = elfcpp::Elf_sizes::sym_size; + + typedef typename Sized_relobj::Output_sections + Output_sections; + typedef Incremental_inputs_reader Inputs_reader; + typedef typename Inputs_reader::Incremental_input_entry_reader + Input_entry_reader; + + // A local symbol. + struct Local_symbol + { + Local_symbol(const char* name_, Address value_, unsigned int size_, + unsigned int shndx_, unsigned int type_, + bool needs_dynsym_entry_) + : st_value(value_), name(name_), st_size(size_), st_shndx(shndx_), + st_type(type_), output_dynsym_index(0), + needs_dynsym_entry(needs_dynsym_entry_) + { } + // The symbol value. + Address st_value; + // The symbol name. This points to the stringpool entry. + const char* name; + // The symbol size. + unsigned int st_size; + // The output section index. + unsigned int st_shndx : 28; + // The symbol type. + unsigned int st_type : 4; + // The index of the symbol in the output dynamic symbol table. + unsigned int output_dynsym_index : 31; + // TRUE if the symbol needs to appear in the dynamic symbol table. + unsigned int needs_dynsym_entry : 1; + }; + + // Return TRUE if this is an incremental (unchanged) input file. + bool + do_is_incremental() const + { return true; } + + // Return the last modified time of the file. + Timespec + do_get_mtime() + { return this->input_reader_.get_mtime(); } + + // Read the symbols. + void + do_read_symbols(Read_symbols_data*); + + // Lay out the input sections. + void + do_layout(Symbol_table*, Layout*, Read_symbols_data*); + + // Layout sections whose layout was deferred while waiting for + // input files from a plugin. + void + do_layout_deferred_sections(Layout*); + + // Add the symbols to the symbol table. + void + do_add_symbols(Symbol_table*, Read_symbols_data*, Layout*); + + Archive::Should_include + do_should_include_member(Symbol_table* symtab, Layout*, Read_symbols_data*, + std::string* why); + + // Iterate over global symbols, calling a visitor class V for each. + void + do_for_all_global_symbols(Read_symbols_data* sd, + Library_base::Symbol_visitor_base* v); + + // Get the size of a section. + uint64_t + do_section_size(unsigned int shndx); + + // Get the name of a section. + std::string + do_section_name(unsigned int shndx); + + // Return a view of the contents of a section. + const unsigned char* + do_section_contents(unsigned int shndx, section_size_type* plen, + bool cache); + + // Return section flags. + uint64_t + do_section_flags(unsigned int shndx); + + // Return section entsize. + uint64_t + do_section_entsize(unsigned int shndx); + + // Return section address. + uint64_t + do_section_address(unsigned int shndx); + + // Return section type. + unsigned int + do_section_type(unsigned int shndx); + + // Return the section link field. + unsigned int + do_section_link(unsigned int shndx); + + // Return the section link field. + unsigned int + do_section_info(unsigned int shndx); + + // Return the section alignment. + uint64_t + do_section_addralign(unsigned int shndx); + + // Return the Xindex structure to use. + Xindex* + do_initialize_xindex(); + + // Get symbol counts. + void + do_get_global_symbol_counts(const Symbol_table*, size_t*, size_t*) const; + + // Get global symbols. + const Symbols* + do_get_global_symbols() const + { return &this->symbols_; } + + // Return the value of a local symbol. + uint64_t + do_local_symbol_value(unsigned int, uint64_t) const + { gold_unreachable(); } + + unsigned int + do_local_plt_offset(unsigned int) const + { gold_unreachable(); } + + bool + do_local_is_tls(unsigned int) const + { gold_unreachable(); } + + // Return the number of local symbols. + unsigned int + do_local_symbol_count() const + { return this->local_symbol_count_; } + + // Return the number of local symbols in the output symbol table. + unsigned int + do_output_local_symbol_count() const + { return this->local_symbol_count_; } + + // Return the file offset for local symbols in the output symbol table. + off_t + do_local_symbol_offset() const + { return this->local_symbol_offset_; } + + // Read the relocs. + void + do_read_relocs(Read_relocs_data*); + + // Process the relocs to find list of referenced sections. Used only + // during garbage collection. + void + do_gc_process_relocs(Symbol_table*, Layout*, Read_relocs_data*); + + // Scan the relocs and adjust the symbol table. + void + do_scan_relocs(Symbol_table*, Layout*, Read_relocs_data*); + + // Count the local symbols. + void + do_count_local_symbols(Stringpool_template*, + Stringpool_template*); + + // Finalize the local symbols. + unsigned int + do_finalize_local_symbols(unsigned int, off_t, Symbol_table*); + + // Set the offset where local dynamic symbol information will be stored. + unsigned int + do_set_local_dynsym_indexes(unsigned int); + + // Set the offset where local dynamic symbol information will be stored. + unsigned int + do_set_local_dynsym_offset(off_t); + + // Relocate the input sections and write out the local symbols. + void + do_relocate(const Symbol_table* symtab, const Layout*, Output_file* of); + + // Set the offset of a section. + void + do_set_section_offset(unsigned int shndx, uint64_t off); + + // The Incremental_binary base file. + Sized_incremental_binary* ibase_; + // The index of the object in the input file list. + unsigned int input_file_index_; + // The reader for the input file. + Input_entry_reader input_reader_; + // The number of local symbols. + unsigned int local_symbol_count_; + // The number of local symbols which go into the output file's dynamic + // symbol table. + unsigned int output_local_dynsym_count_; + // This starting symbol index in the output symbol table. + unsigned int local_symbol_index_; + // The file offset for local symbols in the output symbol table. + unsigned int local_symbol_offset_; + // The file offset for local symbols in the output symbol table. + unsigned int local_dynsym_offset_; + // The entries in the symbol table for the external symbols. + Symbols symbols_; + // Number of symbols defined in object file itself. + size_t defined_count_; + // The offset of the first incremental relocation for this object. + unsigned int incr_reloc_offset_; + // The number of incremental relocations for this object. + unsigned int incr_reloc_count_; + // The index of the first incremental relocation for this object in the + // updated output file. + unsigned int incr_reloc_output_index_; + // A copy of the incremental relocations from this object. + unsigned char* incr_relocs_; + // The local symbols. + std::vector local_symbols_; +}; + +// An incremental Dynobj. This class represents a shared object that has +// not changed since the last incremental link, and whose contents can be +// used directly from the base file. + +template +class Sized_incr_dynobj : public Dynobj +{ + public: + typedef typename elfcpp::Elf_types::Elf_Addr Address; + + static const Address invalid_address = static_cast
(0) - 1; + + Sized_incr_dynobj(const std::string& name, + Sized_incremental_binary* ibase, + unsigned int input_file_index); + + private: + typedef Incremental_inputs_reader Inputs_reader; + typedef typename Inputs_reader::Incremental_input_entry_reader + Input_entry_reader; + + // Return TRUE if this is an incremental (unchanged) input file. + bool + do_is_incremental() const + { return true; } + + // Return the last modified time of the file. + Timespec + do_get_mtime() + { return this->input_reader_.get_mtime(); } + + // Read the symbols. + void + do_read_symbols(Read_symbols_data*); + + // Lay out the input sections. + void + do_layout(Symbol_table*, Layout*, Read_symbols_data*); + + // Add the symbols to the symbol table. + void + do_add_symbols(Symbol_table*, Read_symbols_data*, Layout*); + + Archive::Should_include + do_should_include_member(Symbol_table* symtab, Layout*, Read_symbols_data*, + std::string* why); + + // Iterate over global symbols, calling a visitor class V for each. + void + do_for_all_global_symbols(Read_symbols_data* sd, + Library_base::Symbol_visitor_base* v); + + // Iterate over local symbols, calling a visitor class V for each GOT offset + // associated with a local symbol. + void + do_for_all_local_got_entries(Got_offset_list::Visitor* v) const; + + // Get the size of a section. + uint64_t + do_section_size(unsigned int shndx); + + // Get the name of a section. + std::string + do_section_name(unsigned int shndx); + + // Return a view of the contents of a section. + const unsigned char* + do_section_contents(unsigned int shndx, section_size_type* plen, + bool cache); + + // Return section flags. + uint64_t + do_section_flags(unsigned int shndx); + + // Return section entsize. + uint64_t + do_section_entsize(unsigned int shndx); + + // Return section address. + uint64_t + do_section_address(unsigned int shndx); + + // Return section type. + unsigned int + do_section_type(unsigned int shndx); + + // Return the section link field. + unsigned int + do_section_link(unsigned int shndx); + + // Return the section link field. + unsigned int + do_section_info(unsigned int shndx); + + // Return the section alignment. + uint64_t + do_section_addralign(unsigned int shndx); + + // Return the Xindex structure to use. + Xindex* + do_initialize_xindex(); + + // Get symbol counts. + void + do_get_global_symbol_counts(const Symbol_table*, size_t*, size_t*) const; + + // Get global symbols. + const Symbols* + do_get_global_symbols() const + { return &this->symbols_; } + + // The Incremental_binary base file. + Sized_incremental_binary* ibase_; + // The index of the object in the input file list. + unsigned int input_file_index_; + // The reader for the input file. + Input_entry_reader input_reader_; + // The entries in the symbol table for the external symbols. + Symbols symbols_; + // Number of symbols defined in object file itself. + size_t defined_count_; +}; + +// Allocate an incremental object of the appropriate size and endianness. +extern Object* +make_sized_incremental_object( + Incremental_binary* base, + unsigned int input_file_index, + Incremental_input_type input_type, + const Incremental_binary::Input_reader* input_reader); + +// This class represents an Archive library (or --start-lib/--end-lib group) +// that has not changed since the last incremental link. Its contents come +// from the incremental inputs entry in the base file. + +class Incremental_library : public Library_base +{ + public: + Incremental_library(const char* filename, unsigned int input_file_index, + const Incremental_binary::Input_reader* input_reader) + : Library_base(NULL), filename_(filename), + input_file_index_(input_file_index), input_reader_(input_reader), + unused_symbols_(), is_reported_(false) + { } + + // Return the input file index. + unsigned int + input_file_index() const + { return this->input_file_index_; } + + // Return the serial number of the input file. + unsigned int + arg_serial() const + { return this->input_reader_->arg_serial(); } + + // Copy the unused symbols from the incremental input info. + // We need to do this because we may be overwriting the incremental + // input info in the base file before we write the new incremental + // info. + void + copy_unused_symbols(); + + // Return FALSE on the first call to indicate that the library needs + // to be recorded; return TRUE subsequently. + bool + is_reported() + { + bool was_reported = this->is_reported_; + is_reported_ = true; + return was_reported; + } + + private: + typedef std::vector Symbol_list; + + // The file name. + const std::string& + do_filename() const + { return this->filename_; } + + // Return the modification time of the archive file. + Timespec + do_get_mtime() + { return this->input_reader_->get_mtime(); } + + // Iterator for unused global symbols in the library. + void + do_for_all_unused_symbols(Symbol_visitor_base* v) const; + + // The name of the library. + std::string filename_; + // The input file index of this library. + unsigned int input_file_index_; + // A reader for the incremental input information. + const Incremental_binary::Input_reader* input_reader_; + // List of unused symbols defined in this library. + Symbol_list unused_symbols_; + // TRUE when this library has been reported to the new incremental info. + bool is_reported_; +}; + +} // End namespace gold. + +#endif // !defined(GOLD_INCREMENTAL_H) diff --git a/binutils-2.25/gold/int_encoding.cc b/binutils-2.25/gold/int_encoding.cc new file mode 100644 index 00000000..78874779 --- /dev/null +++ b/binutils-2.25/gold/int_encoding.cc @@ -0,0 +1,134 @@ +// int_encoding.cc -- variable length and unaligned integer encoding support. + +// Copyright 2009, 2010 Free Software Foundation, Inc. +// Written by Doug Kwan by refactoring scattered +// contents from other files in gold. Original code written by Ian +// Lance Taylor and Caleb Howe . + +// 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 + +#include "int_encoding.h" + +namespace gold { + +// Read an unsigned LEB128 number. Each byte contains 7 bits of +// information, plus one bit saying whether the number continues or +// not. BYTE contains the first byte of the number, and is guaranteed +// to have the continuation bit set. + +uint64_t +read_unsigned_LEB_128_x(const unsigned char* buffer, size_t* len, + unsigned char byte) +{ + uint64_t result = static_cast(byte & 0x7f); + size_t num_read = 1; + unsigned int shift = 7; + + do + { + if (num_read > 64 / 7 + 1) + { + gold_warning(_("Unusually large LEB128 decoded, " + "debug information may be corrupted")); + break; + } + byte = *buffer++; + num_read++; + result |= (static_cast(byte & 0x7f)) << shift; + shift += 7; + } + while (byte & 0x80); + + *len = num_read; + + return result; +} + +// Read a signed LEB128 number. These are like regular LEB128 +// numbers, except the last byte may have a sign bit set. +// BYTE contains the first byte of the number, and is guaranteed +// to have the continuation bit set. + +int64_t +read_signed_LEB_128_x(const unsigned char* buffer, size_t* len, + unsigned char byte) +{ + int64_t result = static_cast(byte & 0x7f); + int shift = 7; + size_t num_read = 1; + + do + { + if (num_read > 64 / 7 + 1) + { + gold_warning(_("Unusually large LEB128 decoded, " + "debug information may be corrupted")); + break; + } + byte = *buffer++; + num_read++; + result |= (static_cast(byte & 0x7f) << shift); + shift += 7; + } + while (byte & 0x80); + + if ((shift < 8 * static_cast(sizeof(result))) && (byte & 0x40)) + result |= -((static_cast(1)) << shift); + *len = num_read; + return result; +} + +void +write_unsigned_LEB_128(std::vector* buffer, uint64_t value) +{ + do + { + unsigned char current_byte = value & 0x7f; + value >>= 7; + if (value != 0) + { + current_byte |= 0x80; + } + buffer->push_back(current_byte); + } + while (value != 0); +} + +size_t +get_length_as_unsigned_LEB_128(uint64_t value) +{ + size_t length = 0; + do + { + unsigned char current_byte = value & 0x7f; + value >>= 7; + if (value != 0) + { + current_byte |= 0x80; + } + length++; + } + while (value != 0); + return length; +} + +} // End namespace gold. diff --git a/binutils-2.25/gold/int_encoding.h b/binutils-2.25/gold/int_encoding.h new file mode 100644 index 00000000..467d2244 --- /dev/null +++ b/binutils-2.25/gold/int_encoding.h @@ -0,0 +1,158 @@ +// int_encoding.h -- variable length and unaligned integers -*- C++ -*- + +// Copyright 2009 Free Software Foundation, Inc. +// Written by Doug Kwan by refactoring scattered +// contents from other files in gold. Original code written by Ian +// Lance Taylor and Caleb Howe . + +// 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. + +#ifndef GOLD_INT_ENCODING_H +#define GOLD_INT_ENCODING_H + +#include +#include "elfcpp.h" +#include "target.h" +#include "parameters.h" + +namespace gold +{ + +// +// LEB 128 encoding support. +// + +// Read a ULEB 128 encoded integer from BUFFER. Return the length of the +// encoded integer at the location PLEN. The common case of a single-byte +// value is handled inline, and multi-byte values are processed by the _x +// routine, where BYTE is the first byte of the value. + +uint64_t +read_unsigned_LEB_128_x(const unsigned char* buffer, size_t* plen, + unsigned char byte); + +inline uint64_t +read_unsigned_LEB_128(const unsigned char* buffer, size_t* plen) +{ + unsigned char byte = *buffer++; + + if ((byte & 0x80) != 0) + return read_unsigned_LEB_128_x(buffer, plen, byte); + + *plen = 1; + return static_cast(byte); +} + +// Read an SLEB 128 encoded integer from BUFFER. Return the length of the +// encoded integer at the location PLEN. The common case of a single-byte +// value is handled inline, and multi-byte values are processed by the _x +// routine, where BYTE is the first byte of the value. + +int64_t +read_signed_LEB_128_x(const unsigned char* buffer, size_t* plen, + unsigned char byte); + +inline int64_t +read_signed_LEB_128(const unsigned char* buffer, size_t* plen) +{ + unsigned char byte = *buffer++; + + if ((byte & 0x80) != 0) + return read_signed_LEB_128_x(buffer, plen, byte); + + *plen = 1; + if (byte & 0x40) + return -(static_cast(1) << 7) | static_cast(byte); + return static_cast(byte); +} + +// Write a ULEB 128 encoded VALUE to BUFFER. + +void +write_unsigned_LEB_128(std::vector* buffer, uint64_t value); + +// Return the ULEB 128 encoded size of VALUE. + +size_t +get_length_as_unsigned_LEB_128(uint64_t value); + +// +// Unaligned integer encoding support. +// + +// Insert VALSIZE-bit integer VALUE into DESTINATION. + +template +void insert_into_vector(std::vector* destination, + typename elfcpp::Valtype_base::Valtype value) +{ + unsigned char buffer[valsize / 8]; + if (parameters->target().is_big_endian()) + elfcpp::Swap_unaligned::writeval(buffer, value); + else + elfcpp::Swap_unaligned::writeval(buffer, value); + destination->insert(destination->end(), buffer, buffer + valsize / 8); +} + +// Read a possibly unaligned integer of SIZE from SOURCE. + +template +typename elfcpp::Valtype_base::Valtype +read_from_pointer(const unsigned char* source) +{ + typename elfcpp::Valtype_base::Valtype return_value; + if (parameters->target().is_big_endian()) + return_value = elfcpp::Swap_unaligned::readval(source); + else + return_value = elfcpp::Swap_unaligned::readval(source); + return return_value; +} + +// Read a possibly unaligned integer of SIZE. Update SOURCE after read. + +template +typename elfcpp::Valtype_base::Valtype +read_from_pointer(unsigned char** source) +{ + typename elfcpp::Valtype_base::Valtype return_value; + if (parameters->target().is_big_endian()) + return_value = elfcpp::Swap_unaligned::readval(*source); + else + return_value = elfcpp::Swap_unaligned::readval(*source); + *source += valsize / 8; + return return_value; +} + +// Same as the above except for use with const unsigned char data. + +template +typename elfcpp::Valtype_base::Valtype +read_from_pointer(const unsigned char** source) +{ + typename elfcpp::Valtype_base::Valtype return_value; + if (parameters->target().is_big_endian()) + return_value = elfcpp::Swap_unaligned::readval(*source); + else + return_value = elfcpp::Swap_unaligned::readval(*source); + *source += valsize / 8; + return return_value; +} + +} // End namespace gold. + +#endif // !defined(GOLD_INT_ENCODING_H) diff --git a/binutils-2.25/gold/layout.cc b/binutils-2.25/gold/layout.cc new file mode 100644 index 00000000..38fd272b --- /dev/null +++ b/binutils-2.25/gold/layout.cc @@ -0,0 +1,5909 @@ +// layout.cc -- lay out output file sections for gold + +// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 +// Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include "libiberty.h" +#include "md5.h" +#include "sha1.h" + +#include "parameters.h" +#include "options.h" +#include "mapfile.h" +#include "script.h" +#include "script-sections.h" +#include "output.h" +#include "symtab.h" +#include "dynobj.h" +#include "ehframe.h" +#include "gdb-index.h" +#include "compressed_output.h" +#include "reduced_debug_output.h" +#include "object.h" +#include "reloc.h" +#include "descriptors.h" +#include "plugin.h" +#include "incremental.h" +#include "layout.h" + +namespace gold +{ + +// Class Free_list. + +// The total number of free lists used. +unsigned int Free_list::num_lists = 0; +// The total number of free list nodes used. +unsigned int Free_list::num_nodes = 0; +// The total number of calls to Free_list::remove. +unsigned int Free_list::num_removes = 0; +// The total number of nodes visited during calls to Free_list::remove. +unsigned int Free_list::num_remove_visits = 0; +// The total number of calls to Free_list::allocate. +unsigned int Free_list::num_allocates = 0; +// The total number of nodes visited during calls to Free_list::allocate. +unsigned int Free_list::num_allocate_visits = 0; + +// Initialize the free list. Creates a single free list node that +// describes the entire region of length LEN. If EXTEND is true, +// allocate() is allowed to extend the region beyond its initial +// length. + +void +Free_list::init(off_t len, bool extend) +{ + this->list_.push_front(Free_list_node(0, len)); + this->last_remove_ = this->list_.begin(); + this->extend_ = extend; + this->length_ = len; + ++Free_list::num_lists; + ++Free_list::num_nodes; +} + +// Remove a chunk from the free list. Because we start with a single +// node that covers the entire section, and remove chunks from it one +// at a time, we do not need to coalesce chunks or handle cases that +// span more than one free node. We expect to remove chunks from the +// free list in order, and we expect to have only a few chunks of free +// space left (corresponding to files that have changed since the last +// incremental link), so a simple linear list should provide sufficient +// performance. + +void +Free_list::remove(off_t start, off_t end) +{ + if (start == end) + return; + gold_assert(start < end); + + ++Free_list::num_removes; + + Iterator p = this->last_remove_; + if (p->start_ > start) + p = this->list_.begin(); + + for (; p != this->list_.end(); ++p) + { + ++Free_list::num_remove_visits; + // Find a node that wholly contains the indicated region. + if (p->start_ <= start && p->end_ >= end) + { + // Case 1: the indicated region spans the whole node. + // Add some fuzz to avoid creating tiny free chunks. + if (p->start_ + 3 >= start && p->end_ <= end + 3) + p = this->list_.erase(p); + // Case 2: remove a chunk from the start of the node. + else if (p->start_ + 3 >= start) + p->start_ = end; + // Case 3: remove a chunk from the end of the node. + else if (p->end_ <= end + 3) + p->end_ = start; + // Case 4: remove a chunk from the middle, and split + // the node into two. + else + { + Free_list_node newnode(p->start_, start); + p->start_ = end; + this->list_.insert(p, newnode); + ++Free_list::num_nodes; + } + this->last_remove_ = p; + return; + } + } + + // Did not find a node containing the given chunk. This could happen + // because a small chunk was already removed due to the fuzz. + gold_debug(DEBUG_INCREMENTAL, + "Free_list::remove(%d,%d) not found", + static_cast(start), static_cast(end)); +} + +// Allocate a chunk of size LEN from the free list. Returns -1ULL +// if a sufficiently large chunk of free space is not found. +// We use a simple first-fit algorithm. + +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(len), static_cast(align), + static_cast(minoff)); + if (len == 0) + return align_address(minoff, align); + + ++Free_list::num_allocates; + + // We usually want to drop free chunks smaller than 4 bytes. + // If we need to guarantee a minimum hole size, though, we need + // to keep track of all free chunks. + const int fuzz = this->min_hole_ > 0 ? 0 : 3; + + for (Iterator p = this->list_.begin(); p != this->list_.end(); ++p) + { + ++Free_list::num_allocate_visits; + off_t start = p->start_ > minoff ? p->start_ : minoff; + start = align_address(start, align); + off_t end = start + len; + if (end > p->end_ && p->end_ == this->length_ && this->extend_) + { + this->length_ = end; + p->end_ = end; + } + if (end == p->end_ || (end <= p->end_ - this->min_hole_)) + { + if (p->start_ + fuzz >= start && p->end_ <= end + fuzz) + this->list_.erase(p); + else if (p->start_ + fuzz >= start) + p->start_ = end; + else if (p->end_ <= end + fuzz) + p->end_ = start; + else + { + Free_list_node newnode(p->start_, start); + p->start_ = end; + this->list_.insert(p, newnode); + ++Free_list::num_nodes; + } + return start; + } + } + if (this->extend_) + { + off_t start = align_address(this->length_, align); + this->length_ = start + len; + return start; + } + return -1; +} + +// Dump the free list (for debugging). +void +Free_list::dump() +{ + gold_info("Free list:\n start end length\n"); + for (Iterator p = this->list_.begin(); p != this->list_.end(); ++p) + gold_info(" %08lx %08lx %08lx", static_cast(p->start_), + static_cast(p->end_), + static_cast(p->end_ - p->start_)); +} + +// Print the statistics for the free lists. +void +Free_list::print_stats() +{ + fprintf(stderr, _("%s: total free lists: %u\n"), + program_name, Free_list::num_lists); + fprintf(stderr, _("%s: total free list nodes: %u\n"), + program_name, Free_list::num_nodes); + fprintf(stderr, _("%s: calls to Free_list::remove: %u\n"), + program_name, Free_list::num_removes); + fprintf(stderr, _("%s: nodes visited: %u\n"), + program_name, Free_list::num_remove_visits); + fprintf(stderr, _("%s: calls to Free_list::allocate: %u\n"), + program_name, Free_list::num_allocates); + fprintf(stderr, _("%s: nodes visited: %u\n"), + program_name, Free_list::num_allocate_visits); +} + +// A Hash_task computes the MD5 checksum of an array of char. +// It has a blocker on either side (i.e., the task cannot run until +// the first is unblocked, and it unblocks the second after running). + +class Hash_task : public Task +{ + public: + Hash_task(const unsigned char* src, + size_t size, + unsigned char* dst, + Task_token* build_id_blocker, + Task_token* final_blocker) + : src_(src), size_(size), dst_(dst), build_id_blocker_(build_id_blocker), + final_blocker_(final_blocker) + { } + + void + run(Workqueue*) + { md5_buffer(reinterpret_cast(src_), size_, dst_); } + + Task_token* + is_runnable(); + + // Unblock FINAL_BLOCKER_ when done. + void + locks(Task_locker* tl) + { tl->add(this, this->final_blocker_); } + + std::string + get_name() const + { return "Hash_task"; } + + private: + const unsigned char* const src_; + const size_t size_; + unsigned char* const dst_; + Task_token* const build_id_blocker_; + Task_token* const final_blocker_; +}; + +Task_token* +Hash_task::is_runnable() +{ + if (this->build_id_blocker_->is_blocked()) + return this->build_id_blocker_; + return NULL; +} + +// Layout::Relaxation_debug_check methods. + +// Check that sections and special data are in reset states. +// We do not save states for Output_sections and special Output_data. +// So we check that they have not assigned any addresses or offsets. +// clean_up_after_relaxation simply resets their addresses and offsets. +void +Layout::Relaxation_debug_check::check_output_data_for_reset_values( + const Layout::Section_list& sections, + const Layout::Data_list& special_outputs, + const Layout::Data_list& relax_outputs) +{ + for(Layout::Section_list::const_iterator p = sections.begin(); + p != sections.end(); + ++p) + gold_assert((*p)->address_and_file_offset_have_reset_values()); + + for(Layout::Data_list::const_iterator p = special_outputs.begin(); + p != special_outputs.end(); + ++p) + gold_assert((*p)->address_and_file_offset_have_reset_values()); + + gold_assert(relax_outputs.empty()); +} + +// Save information of SECTIONS for checking later. + +void +Layout::Relaxation_debug_check::read_sections( + const Layout::Section_list& sections) +{ + for(Layout::Section_list::const_iterator p = sections.begin(); + p != sections.end(); + ++p) + { + Output_section* os = *p; + Section_info info; + info.output_section = os; + info.address = os->is_address_valid() ? os->address() : 0; + info.data_size = os->is_data_size_valid() ? os->data_size() : -1; + info.offset = os->is_offset_valid()? os->offset() : -1 ; + this->section_infos_.push_back(info); + } +} + +// Verify SECTIONS using previously recorded information. + +void +Layout::Relaxation_debug_check::verify_sections( + const Layout::Section_list& sections) +{ + size_t i = 0; + for(Layout::Section_list::const_iterator p = sections.begin(); + p != sections.end(); + ++p, ++i) + { + Output_section* os = *p; + uint64_t address = os->is_address_valid() ? os->address() : 0; + off_t data_size = os->is_data_size_valid() ? os->data_size() : -1; + off_t offset = os->is_offset_valid()? os->offset() : -1 ; + + if (i >= this->section_infos_.size()) + { + gold_fatal("Section_info of %s missing.\n", os->name()); + } + const Section_info& info = this->section_infos_[i]; + if (os != info.output_section) + gold_fatal("Section order changed. Expecting %s but see %s\n", + info.output_section->name(), os->name()); + if (address != info.address + || data_size != info.data_size + || offset != info.offset) + gold_fatal("Section %s changed.\n", os->name()); + } +} + +// Layout_task_runner methods. + +// Lay out the sections. This is called after all the input objects +// have been read. + +void +Layout_task_runner::run(Workqueue* workqueue, const Task* task) +{ + // See if any of the input definitions violate the One Definition Rule. + // TODO: if this is too slow, do this as a task, rather than inline. + this->symtab_->detect_odr_violations(task, this->options_.output_file_name()); + + Layout* layout = this->layout_; + off_t file_size = layout->finalize(this->input_objects_, + this->symtab_, + this->target_, + task); + + // Now we know the final size of the output file and we know where + // each piece of information goes. + + if (this->mapfile_ != NULL) + { + this->mapfile_->print_discarded_sections(this->input_objects_); + layout->print_to_mapfile(this->mapfile_); + } + + Output_file* of; + if (layout->incremental_base() == NULL) + { + of = new Output_file(parameters->options().output_file_name()); + if (this->options_.oformat_enum() != General_options::OBJECT_FORMAT_ELF) + of->set_is_temporary(); + of->open(file_size); + } + else + { + of = layout->incremental_base()->output_file(); + + // Apply the incremental relocations for symbols whose values + // have changed. We do this before we resize the file and start + // writing anything else to it, so that we can read the old + // incremental information from the file before (possibly) + // overwriting it. + if (parameters->incremental_update()) + layout->incremental_base()->apply_incremental_relocs(this->symtab_, + this->layout_, + of); + + of->resize(file_size); + } + + // Queue up the final set of tasks. + gold::queue_final_tasks(this->options_, this->input_objects_, + this->symtab_, layout, workqueue, of); +} + +// Layout methods. + +Layout::Layout(int number_of_input_files, Script_options* script_options) + : number_of_input_files_(number_of_input_files), + script_options_(script_options), + namepool_(), + sympool_(), + dynpool_(), + signatures_(), + section_name_map_(), + segment_list_(), + section_list_(), + unattached_section_list_(), + special_output_list_(), + relax_output_list_(), + section_headers_(NULL), + tls_segment_(NULL), + relro_segment_(NULL), + interp_segment_(NULL), + increase_relro_(0), + symtab_section_(NULL), + symtab_xindex_(NULL), + dynsym_section_(NULL), + dynsym_xindex_(NULL), + dynamic_section_(NULL), + dynamic_symbol_(NULL), + dynamic_data_(NULL), + eh_frame_section_(NULL), + eh_frame_data_(NULL), + added_eh_frame_data_(false), + eh_frame_hdr_section_(NULL), + gdb_index_data_(NULL), + build_id_note_(NULL), + array_of_hashes_(NULL), + size_of_array_of_hashes_(0), + input_view_(NULL), + debug_abbrev_(NULL), + debug_info_(NULL), + group_signatures_(), + output_file_size_(-1), + have_added_input_section_(false), + sections_are_attached_(false), + input_requires_executable_stack_(false), + input_with_gnu_stack_note_(false), + input_without_gnu_stack_note_(false), + has_static_tls_(false), + any_postprocessing_sections_(false), + resized_signatures_(false), + have_stabstr_section_(false), + section_ordering_specified_(false), + unique_segment_for_sections_specified_(false), + incremental_inputs_(NULL), + record_output_section_data_from_script_(false), + script_output_section_data_list_(), + segment_states_(NULL), + relaxation_debug_check_(NULL), + section_order_map_(), + section_segment_map_(), + input_section_position_(), + input_section_glob_(), + incremental_base_(NULL), + free_list_() +{ + // Make space for more than enough segments for a typical file. + // This is just for efficiency--it's OK if we wind up needing more. + this->segment_list_.reserve(12); + + // We expect two unattached Output_data objects: the file header and + // the segment headers. + this->special_output_list_.reserve(2); + + // Initialize structure needed for an incremental build. + if (parameters->incremental()) + this->incremental_inputs_ = new Incremental_inputs; + + // The section name pool is worth optimizing in all cases, because + // it is small, but there are often overlaps due to .rel sections. + this->namepool_.set_optimize(); +} + +// For incremental links, record the base file to be modified. + +void +Layout::set_incremental_base(Incremental_binary* base) +{ + this->incremental_base_ = base; + this->free_list_.init(base->output_file()->filesize(), true); +} + +// Hash a key we use to look up an output section mapping. + +size_t +Layout::Hash_key::operator()(const Layout::Key& k) const +{ + return k.first + k.second.first + k.second.second; +} + +// These are the debug sections that are actually used by gdb. +// Currently, we've checked versions of gdb up to and including 7.4. +// We only check the part of the name that follows ".debug_" or +// ".zdebug_". + +static const char* gdb_sections[] = +{ + "abbrev", + "addr", // Fission extension + // "aranges", // not used by gdb as of 7.4 + "frame", + "info", + "types", + "line", + "loc", + "macinfo", + "macro", + // "pubnames", // not used by gdb as of 7.4 + // "pubtypes", // not used by gdb as of 7.4 + "ranges", + "str", +}; + +// This is the minimum set of sections needed for line numbers. + +static const char* lines_only_debug_sections[] = +{ + "abbrev", + // "addr", // Fission extension + // "aranges", // not used by gdb as of 7.4 + // "frame", + "info", + // "types", + "line", + // "loc", + // "macinfo", + // "macro", + // "pubnames", // not used by gdb as of 7.4 + // "pubtypes", // not used by gdb as of 7.4 + // "ranges", + "str", +}; + +// These sections are the DWARF fast-lookup tables, and are not needed +// when building a .gdb_index section. + +static const char* gdb_fast_lookup_sections[] = +{ + "aranges", + "pubnames", + "pubtypes", +}; + +// Returns whether the given debug section is in the list of +// debug-sections-used-by-some-version-of-gdb. SUFFIX is the +// portion of the name following ".debug_" or ".zdebug_". + +static inline bool +is_gdb_debug_section(const char* suffix) +{ + // We can do this faster: binary search or a hashtable. But why bother? + for (size_t i = 0; i < sizeof(gdb_sections)/sizeof(*gdb_sections); ++i) + if (strcmp(suffix, gdb_sections[i]) == 0) + return true; + return false; +} + +// Returns whether the given section is needed for lines-only debugging. + +static inline bool +is_lines_only_debug_section(const char* suffix) +{ + // We can do this faster: binary search or a hashtable. But why bother? + for (size_t i = 0; + i < sizeof(lines_only_debug_sections)/sizeof(*lines_only_debug_sections); + ++i) + if (strcmp(suffix, lines_only_debug_sections[i]) == 0) + return true; + return false; +} + +// Returns whether the given section is a fast-lookup section that +// will not be needed when building a .gdb_index section. + +static inline bool +is_gdb_fast_lookup_section(const char* suffix) +{ + // We can do this faster: binary search or a hashtable. But why bother? + for (size_t i = 0; + i < sizeof(gdb_fast_lookup_sections)/sizeof(*gdb_fast_lookup_sections); + ++i) + if (strcmp(suffix, gdb_fast_lookup_sections[i]) == 0) + return true; + return false; +} + +// Sometimes we compress sections. This is typically done for +// sections that are not part of normal program execution (such as +// .debug_* sections), and where the readers of these sections know +// how to deal with compressed sections. This routine doesn't say for +// certain whether we'll compress -- it depends on commandline options +// as well -- just whether this section is a candidate for compression. +// (The Output_compressed_section class decides whether to compress +// a given section, and picks the name of the compressed section.) + +static bool +is_compressible_debug_section(const char* secname) +{ + return (is_prefix_of(".debug", secname)); +} + +// We may see compressed debug sections in input files. Return TRUE +// if this is the name of a compressed debug section. + +bool +is_compressed_debug_section(const char* secname) +{ + return (is_prefix_of(".zdebug", secname)); +} + +// Whether to include this section in the link. + +template +bool +Layout::include_section(Sized_relobj_file*, const char* name, + const elfcpp::Shdr& shdr) +{ + if (!parameters->options().relocatable() + && (shdr.get_sh_flags() & elfcpp::SHF_EXCLUDE)) + return false; + + switch (shdr.get_sh_type()) + { + case elfcpp::SHT_NULL: + case elfcpp::SHT_SYMTAB: + case elfcpp::SHT_DYNSYM: + case elfcpp::SHT_HASH: + case elfcpp::SHT_DYNAMIC: + case elfcpp::SHT_SYMTAB_SHNDX: + return false; + + case elfcpp::SHT_STRTAB: + // Discard the sections which have special meanings in the ELF + // ABI. Keep others (e.g., .stabstr). We could also do this by + // checking the sh_link fields of the appropriate sections. + return (strcmp(name, ".dynstr") != 0 + && strcmp(name, ".strtab") != 0 + && strcmp(name, ".shstrtab") != 0); + + case elfcpp::SHT_RELA: + case elfcpp::SHT_REL: + case elfcpp::SHT_GROUP: + // If we are emitting relocations these should be handled + // elsewhere. + gold_assert(!parameters->options().relocatable()); + return false; + + case elfcpp::SHT_PROGBITS: + if (parameters->options().strip_debug() + && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0) + { + if (is_debug_info_section(name)) + return false; + } + if (parameters->options().strip_debug_non_line() + && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0) + { + // Debugging sections can only be recognized by name. + if (is_prefix_of(".debug_", name) + && !is_lines_only_debug_section(name + 7)) + return false; + if (is_prefix_of(".zdebug_", name) + && !is_lines_only_debug_section(name + 8)) + return false; + } + if (parameters->options().strip_debug_gdb() + && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0) + { + // Debugging sections can only be recognized by name. + if (is_prefix_of(".debug_", name) + && !is_gdb_debug_section(name + 7)) + return false; + if (is_prefix_of(".zdebug_", name) + && !is_gdb_debug_section(name + 8)) + return false; + } + if (parameters->options().gdb_index() + && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0) + { + // When building .gdb_index, we can strip .debug_pubnames, + // .debug_pubtypes, and .debug_aranges sections. + if (is_prefix_of(".debug_", name) + && is_gdb_fast_lookup_section(name + 7)) + return false; + if (is_prefix_of(".zdebug_", name) + && is_gdb_fast_lookup_section(name + 8)) + 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; + } + // The GNU linker strips .gnu_debuglink sections, so we do too. + // This is a feature used to keep debugging information in + // separate files. + if (strcmp(name, ".gnu_debuglink") == 0) + return false; + return true; + + default: + return true; + } +} + +// Return an output section named NAME, or NULL if there is none. + +Output_section* +Layout::find_output_section(const char* name) const +{ + for (Section_list::const_iterator p = this->section_list_.begin(); + p != this->section_list_.end(); + ++p) + if (strcmp((*p)->name(), name) == 0) + return *p; + return NULL; +} + +// Return an output segment of type TYPE, with segment flags SET set +// and segment flags CLEAR clear. Return NULL if there is none. + +Output_segment* +Layout::find_output_segment(elfcpp::PT type, elfcpp::Elf_Word set, + elfcpp::Elf_Word clear) const +{ + for (Segment_list::const_iterator p = this->segment_list_.begin(); + p != this->segment_list_.end(); + ++p) + if (static_cast((*p)->type()) == type + && ((*p)->flags() & set) == set + && ((*p)->flags() & clear) == 0) + return *p; + return NULL; +} + +// When we put a .ctors or .dtors section with more than one word into +// a .init_array or .fini_array section, we need to reverse the words +// in the .ctors/.dtors section. This is because .init_array executes +// constructors front to back, where .ctors executes them back to +// front, and vice-versa for .fini_array/.dtors. Although we do want +// to remap .ctors/.dtors into .init_array/.fini_array because it can +// be more efficient, we don't want to change the order in which +// constructors/destructors are run. This set just keeps track of +// these sections which need to be reversed. It is only changed by +// Layout::layout. It should be a private member of Layout, but that +// would require layout.h to #include object.h to get the definition +// of Section_id. +static Unordered_set ctors_sections_in_init_array; + +// Return whether OBJECT/SHNDX is a .ctors/.dtors section mapped to a +// .init_array/.fini_array section. + +bool +Layout::is_ctors_in_init_array(Relobj* relobj, unsigned int shndx) const +{ + return (ctors_sections_in_init_array.find(Section_id(relobj, shndx)) + != ctors_sections_in_init_array.end()); +} + +// Return the output section to use for section NAME with type TYPE +// and section flags FLAGS. NAME must be canonicalized in the string +// pool, and NAME_KEY is the key. ORDER is where this should appear +// in the output sections. IS_RELRO is true for a relro section. + +Output_section* +Layout::get_output_section(const char* name, Stringpool::Key name_key, + elfcpp::Elf_Word type, elfcpp::Elf_Xword flags, + Output_section_order order, bool is_relro) +{ + elfcpp::Elf_Word lookup_type = type; + + // For lookup purposes, treat INIT_ARRAY, FINI_ARRAY, and + // PREINIT_ARRAY like PROGBITS. This ensures that we combine + // .init_array, .fini_array, and .preinit_array sections by name + // whatever their type in the input file. We do this because the + // types are not always right in the input files. + if (lookup_type == elfcpp::SHT_INIT_ARRAY + || lookup_type == elfcpp::SHT_FINI_ARRAY + || lookup_type == elfcpp::SHT_PREINIT_ARRAY) + lookup_type = elfcpp::SHT_PROGBITS; + + elfcpp::Elf_Xword lookup_flags = flags; + + // Ignoring SHF_WRITE and SHF_EXECINSTR here means that we combine + // read-write with read-only sections. Some other ELF linkers do + // not do this. FIXME: Perhaps there should be an option + // controlling this. + lookup_flags &= ~(elfcpp::SHF_WRITE | elfcpp::SHF_EXECINSTR); + + const Key key(name_key, std::make_pair(lookup_type, lookup_flags)); + const std::pair v(key, NULL); + std::pair ins( + this->section_name_map_.insert(v)); + + if (!ins.second) + return ins.first->second; + else + { + // This is the first time we've seen this name/type/flags + // combination. For compatibility with the GNU linker, we + // combine sections with contents and zero flags with sections + // with non-zero flags. This is a workaround for cases where + // assembler code forgets to set section flags. FIXME: Perhaps + // there should be an option to control this. + Output_section* os = NULL; + + 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 + || 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, + zero_flags)); + 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) + os = this->make_output_section(name, type, flags, order, is_relro); + + ins.first->second = os; + return os; + } +} + +// Returns TRUE iff NAME (an input section from RELOBJ) will +// be mapped to an output section that should be KEPT. + +bool +Layout::keep_input_section(const Relobj* relobj, const char* name) +{ + if (! this->script_options_->saw_sections_clause()) + return false; + + Script_sections* ss = this->script_options_->script_sections(); + const char* file_name = relobj == NULL ? NULL : relobj->name().c_str(); + Output_section** output_section_slot; + Script_sections::Section_type script_section_type; + bool keep; + + name = ss->output_section_name(file_name, name, &output_section_slot, + &script_section_type, &keep); + return name != NULL && keep; +} + +// Clear the input section flags that should not be copied to the +// output section. + +elfcpp::Elf_Xword +Layout::get_output_section_flags(elfcpp::Elf_Xword input_section_flags) +{ + // Some flags in the input section should not be automatically + // copied to the output section. + input_section_flags &= ~ (elfcpp::SHF_INFO_LINK + | elfcpp::SHF_GROUP + | elfcpp::SHF_MERGE + | elfcpp::SHF_STRINGS); + + // We only clear the SHF_LINK_ORDER flag in for + // a non-relocatable link. + if (!parameters->options().relocatable()) + input_section_flags &= ~elfcpp::SHF_LINK_ORDER; + + return input_section_flags; +} + +// Pick the output section to use for section NAME, in input file +// RELOBJ, with type TYPE and flags FLAGS. RELOBJ may be NULL for a +// linker created section. IS_INPUT_SECTION is true if we are +// choosing an output section for an input section found in a input +// file. ORDER is where this section should appear in the output +// sections. IS_RELRO is true for a relro section. This will return +// NULL if the input section should be discarded. + +Output_section* +Layout::choose_output_section(const Relobj* relobj, const char* name, + elfcpp::Elf_Word type, elfcpp::Elf_Xword flags, + bool is_input_section, Output_section_order order, + bool is_relro) +{ + // We should not see any input sections after we have attached + // sections to segments. + gold_assert(!is_input_section || !this->sections_are_attached_); + + flags = this->get_output_section_flags(flags); + + if (this->script_options_->saw_sections_clause()) + { + // We are using a SECTIONS clause, so the output section is + // chosen based only on the name. + + Script_sections* ss = this->script_options_->script_sections(); + const char* file_name = relobj == NULL ? NULL : relobj->name().c_str(); + Output_section** output_section_slot; + Script_sections::Section_type script_section_type; + const char* orig_name = name; + bool keep; + name = ss->output_section_name(file_name, name, &output_section_slot, + &script_section_type, &keep); + + if (name == NULL) + { + gold_debug(DEBUG_SCRIPT, _("Unable to create output section '%s' " + "because it is not allowed by the " + "SECTIONS clause of the linker script"), + orig_name); + // The SECTIONS clause says to discard this input section. + return NULL; + } + + // We can only handle script section types ST_NONE and ST_NOLOAD. + switch (script_section_type) + { + case Script_sections::ST_NONE: + break; + case Script_sections::ST_NOLOAD: + flags &= elfcpp::SHF_ALLOC; + break; + default: + gold_unreachable(); + } + + // If this is an orphan section--one not mentioned in the linker + // script--then OUTPUT_SECTION_SLOT will be NULL, and we do the + // default processing below. + + if (output_section_slot != NULL) + { + if (*output_section_slot != NULL) + { + (*output_section_slot)->update_flags_for_input_section(flags); + return *output_section_slot; + } + + // We don't put sections found in the linker script into + // SECTION_NAME_MAP_. That keeps us from getting confused + // if an orphan section is mapped to a section with the same + // name as one in the linker script. + + name = this->namepool_.add(name, false, NULL); + + Output_section* os = this->make_output_section(name, type, flags, + order, is_relro); + + os->set_found_in_sections_clause(); + + // Special handling for NOLOAD sections. + if (script_section_type == Script_sections::ST_NOLOAD) + { + os->set_is_noload(); + + // The constructor of Output_section sets addresses of non-ALLOC + // sections to 0 by default. We don't want that for NOLOAD + // sections even if they have no SHF_ALLOC flag. + if ((os->flags() & elfcpp::SHF_ALLOC) == 0 + && os->is_address_valid()) + { + gold_assert(os->address() == 0 + && !os->is_offset_valid() + && !os->is_data_size_valid()); + os->reset_address_and_file_offset(); + } + } + + *output_section_slot = os; + return os; + } + } + + // FIXME: Handle SHF_OS_NONCONFORMING somewhere. + + size_t len = strlen(name); + char* uncompressed_name = NULL; + + // Compressed debug sections should be mapped to the corresponding + // uncompressed section. + if (is_compressed_debug_section(name)) + { + uncompressed_name = new char[len]; + uncompressed_name[0] = '.'; + gold_assert(name[0] == '.' && name[1] == 'z'); + strncpy(&uncompressed_name[1], &name[2], len - 2); + uncompressed_name[len - 1] = '\0'; + len -= 1; + name = uncompressed_name; + } + + // Turn NAME from the name of the input section into the name of the + // output section. + if (is_input_section + && !this->script_options_->saw_sections_clause() + && !parameters->options().relocatable()) + { + const char *orig_name = name; + name = parameters->target().output_section_name(relobj, name, &len); + if (name == NULL) + name = Layout::output_section_name(relobj, orig_name, &len); + } + + Stringpool::Key name_key; + name = this->namepool_.add_with_length(name, len, true, &name_key); + + if (uncompressed_name != NULL) + delete[] uncompressed_name; + + // Find or make the output section. The output section is selected + // based on the section name, type, and flags. + return this->get_output_section(name, name_key, type, flags, order, is_relro); +} + +// For incremental links, record the initial fixed layout of a section +// from the base file, and return a pointer to the Output_section. + +template +Output_section* +Layout::init_fixed_output_section(const char* name, + elfcpp::Shdr& shdr) +{ + unsigned int sh_type = shdr.get_sh_type(); + + // We preserve the layout of PROGBITS, NOBITS, INIT_ARRAY, FINI_ARRAY, + // PRE_INIT_ARRAY, and NOTE sections. + // All others will be created from scratch and reallocated. + if (!can_incremental_update(sh_type)) + return NULL; + + // If we're generating a .gdb_index section, we need to regenerate + // it from scratch. + if (parameters->options().gdb_index() + && sh_type == elfcpp::SHT_PROGBITS + && strcmp(name, ".gdb_index") == 0) + return NULL; + + typename elfcpp::Elf_types::Elf_Addr sh_addr = shdr.get_sh_addr(); + typename elfcpp::Elf_types::Elf_Off sh_offset = shdr.get_sh_offset(); + typename elfcpp::Elf_types::Elf_WXword sh_size = shdr.get_sh_size(); + typename elfcpp::Elf_types::Elf_WXword sh_flags = shdr.get_sh_flags(); + typename elfcpp::Elf_types::Elf_WXword sh_addralign = + shdr.get_sh_addralign(); + + // Make the output section. + 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); + 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); + return os; +} + +// Return the index by which an input section should be ordered. This +// is used to sort some .text sections, for compatibility with GNU ld. + +int +Layout::special_ordering_of_input_section(const char* name) +{ + // The GNU linker has some special handling for some sections that + // wind up in the .text section. Sections that start with these + // prefixes must appear first, and must appear in the order listed + // here. + static const char* const text_section_sort[] = + { + ".text.unlikely", + ".text.exit", + ".text.startup", + ".text.hot" + }; + + for (size_t i = 0; + i < sizeof(text_section_sort) / sizeof(text_section_sort[0]); + i++) + if (is_prefix_of(text_section_sort[i], name)) + return i; + + return -1; +} + +// Return the output section to use for input section SHNDX, with name +// NAME, with header HEADER, from object OBJECT. RELOC_SHNDX is the +// index of a relocation section which applies to this section, or 0 +// if none, or -1U if more than one. RELOC_TYPE is the type of the +// relocation section if there is one. Set *OFF to the offset of this +// input section without the output section. Return NULL if the +// section should be discarded. Set *OFF to -1 if the section +// contents should not be written directly to the output file, but +// will instead receive special handling. + +template +Output_section* +Layout::layout(Sized_relobj_file* object, unsigned int shndx, + const char* name, const elfcpp::Shdr& shdr, + unsigned int reloc_shndx, unsigned int, off_t* off) +{ + *off = 0; + + if (!this->include_section(object, name, shdr)) + return NULL; + + elfcpp::Elf_Word sh_type = shdr.get_sh_type(); + + // In a relocatable link a grouped section must not be combined with + // any other sections. + Output_section* os; + if (parameters->options().relocatable() + && (shdr.get_sh_flags() & elfcpp::SHF_GROUP) != 0) + { + name = this->namepool_.add(name, true, NULL); + os = this->make_output_section(name, sh_type, shdr.get_sh_flags(), + ORDER_INVALID, false); + } + else + { + // Plugins can choose to place one or more subsets of sections in + // unique segments and this is done by mapping these section subsets + // to unique output sections. Check if this section needs to be + // remapped to a unique output section. + Section_segment_map::iterator it + = this->section_segment_map_.find(Const_section_id(object, shndx)); + if (it == this->section_segment_map_.end()) + { + os = this->choose_output_section(object, name, sh_type, + shdr.get_sh_flags(), true, + ORDER_INVALID, false); + } + else + { + // We know the name of the output section, directly call + // get_output_section here by-passing choose_output_section. + elfcpp::Elf_Xword flags + = this->get_output_section_flags(shdr.get_sh_flags()); + + const char* os_name = it->second->name; + Stringpool::Key name_key; + os_name = this->namepool_.add(os_name, true, &name_key); + os = this->get_output_section(os_name, name_key, sh_type, flags, + ORDER_INVALID, false); + if (!os->is_unique_segment()) + { + os->set_is_unique_segment(); + os->set_extra_segment_flags(it->second->flags); + os->set_segment_alignment(it->second->align); + } + } + if (os == NULL) + return NULL; + } + + // By default the GNU linker sorts input sections whose names match + // .ctors.*, .dtors.*, .init_array.*, or .fini_array.*. The + // sections are sorted by name. This is used to implement + // constructor priority ordering. We are compatible. When we put + // .ctor sections in .init_array and .dtor sections in .fini_array, + // we must also sort plain .ctor and .dtor sections. + if (!this->script_options_->saw_sections_clause() + && !parameters->options().relocatable() + && (is_prefix_of(".ctors.", name) + || is_prefix_of(".dtors.", name) + || is_prefix_of(".init_array.", name) + || is_prefix_of(".fini_array.", name) + || (parameters->options().ctors_in_init_array() + && (strcmp(name, ".ctors") == 0 + || strcmp(name, ".dtors") == 0)))) + os->set_must_sort_attached_input_sections(); + + // By default the GNU linker sorts some special text sections ahead + // of others. We are compatible. + if (parameters->options().text_reorder() + && !this->script_options_->saw_sections_clause() + && !this->is_section_ordering_specified() + && !parameters->options().relocatable() + && Layout::special_ordering_of_input_section(name) >= 0) + os->set_must_sort_attached_input_sections(); + + // If this is a .ctors or .ctors.* section being mapped to a + // .init_array section, or a .dtors or .dtors.* section being mapped + // to a .fini_array section, we will need to reverse the words if + // there is more than one. Record this section for later. See + // ctors_sections_in_init_array above. + if (!this->script_options_->saw_sections_clause() + && !parameters->options().relocatable() + && shdr.get_sh_size() > size / 8 + && (((strcmp(name, ".ctors") == 0 + || is_prefix_of(".ctors.", name)) + && strcmp(os->name(), ".init_array") == 0) + || ((strcmp(name, ".dtors") == 0 + || is_prefix_of(".dtors.", name)) + && strcmp(os->name(), ".fini_array") == 0))) + ctors_sections_in_init_array.insert(Section_id(object, shndx)); + + // FIXME: Handle SHF_LINK_ORDER somewhere. + + elfcpp::Elf_Xword orig_flags = os->flags(); + + *off = os->add_input_section(this, object, shndx, name, shdr, reloc_shndx, + this->script_options_->saw_sections_clause()); + + // If the flags changed, we may have to change the order. + if ((orig_flags & elfcpp::SHF_ALLOC) != 0) + { + orig_flags &= (elfcpp::SHF_WRITE | elfcpp::SHF_EXECINSTR); + elfcpp::Elf_Xword new_flags = + os->flags() & (elfcpp::SHF_WRITE | elfcpp::SHF_EXECINSTR); + if (orig_flags != new_flags) + os->set_order(this->default_section_order(os, false)); + } + + this->have_added_input_section_ = true; + + return os; +} + +// Maps section SECN to SEGMENT s. +void +Layout::insert_section_segment_map(Const_section_id secn, + Unique_segment_info *s) +{ + gold_assert(this->unique_segment_for_sections_specified_); + this->section_segment_map_[secn] = s; +} + +// Handle a relocation section when doing a relocatable link. + +template +Output_section* +Layout::layout_reloc(Sized_relobj_file* object, + unsigned int, + const elfcpp::Shdr& shdr, + Output_section* data_section, + Relocatable_relocs* rr) +{ + gold_assert(parameters->options().relocatable() + || parameters->options().emit_relocs()); + + int sh_type = shdr.get_sh_type(); + + std::string name; + if (sh_type == elfcpp::SHT_REL) + name = ".rel"; + else if (sh_type == elfcpp::SHT_RELA) + name = ".rela"; + else + gold_unreachable(); + name += data_section->name(); + + // In a relocatable link relocs for a grouped section must not be + // combined with other reloc sections. + Output_section* os; + if (!parameters->options().relocatable() + || (data_section->flags() & elfcpp::SHF_GROUP) == 0) + os = this->choose_output_section(object, name.c_str(), sh_type, + shdr.get_sh_flags(), false, + ORDER_INVALID, false); + else + { + const char* n = this->namepool_.add(name.c_str(), true, NULL); + os = this->make_output_section(n, sh_type, shdr.get_sh_flags(), + ORDER_INVALID, false); + } + + os->set_should_link_to_symtab(); + os->set_info_section(data_section); + + Output_section_data* posd; + if (sh_type == elfcpp::SHT_REL) + { + os->set_entsize(elfcpp::Elf_sizes::rel_size); + posd = new Output_relocatable_relocs(rr); + } + else if (sh_type == elfcpp::SHT_RELA) + { + os->set_entsize(elfcpp::Elf_sizes::rela_size); + posd = new Output_relocatable_relocs(rr); + } + else + gold_unreachable(); + + os->add_output_section_data(posd); + rr->set_output_data(posd); + + return os; +} + +// Handle a group section when doing a relocatable link. + +template +void +Layout::layout_group(Symbol_table* symtab, + Sized_relobj_file* object, + unsigned int, + const char* group_section_name, + const char* signature, + const elfcpp::Shdr& shdr, + elfcpp::Elf_Word flags, + std::vector* shndxes) +{ + gold_assert(parameters->options().relocatable()); + gold_assert(shdr.get_sh_type() == elfcpp::SHT_GROUP); + group_section_name = this->namepool_.add(group_section_name, true, NULL); + Output_section* os = this->make_output_section(group_section_name, + elfcpp::SHT_GROUP, + shdr.get_sh_flags(), + ORDER_INVALID, false); + + // We need to find a symbol with the signature in the symbol table. + // If we don't find one now, we need to look again later. + Symbol* sym = symtab->lookup(signature, NULL); + if (sym != NULL) + os->set_info_symndx(sym); + else + { + // Reserve some space to minimize reallocations. + if (this->group_signatures_.empty()) + this->group_signatures_.reserve(this->number_of_input_files_ * 16); + + // We will wind up using a symbol whose name is the signature. + // So just put the signature in the symbol name pool to save it. + signature = symtab->canonicalize_name(signature); + this->group_signatures_.push_back(Group_signature(os, signature)); + } + + os->set_should_link_to_symtab(); + os->set_entsize(4); + + section_size_type entry_count = + convert_to_section_size_type(shdr.get_sh_size() / 4); + Output_section_data* posd = + new Output_data_group(object, entry_count, flags, + shndxes); + os->add_output_section_data(posd); +} + +// Special GNU handling of sections name .eh_frame. They will +// normally hold exception frame data as defined by the C++ ABI +// (http://codesourcery.com/cxx-abi/). + +template +Output_section* +Layout::layout_eh_frame(Sized_relobj_file* object, + const unsigned char* symbols, + off_t symbols_size, + const unsigned char* symbol_names, + off_t symbol_names_size, + unsigned int shndx, + const elfcpp::Shdr& shdr, + unsigned int reloc_shndx, unsigned int reloc_type, + off_t* off) +{ + gold_assert(shdr.get_sh_type() == elfcpp::SHT_PROGBITS + || shdr.get_sh_type() == elfcpp::SHT_X86_64_UNWIND); + gold_assert((shdr.get_sh_flags() & elfcpp::SHF_ALLOC) != 0); + + Output_section* os = this->make_eh_frame_section(object); + if (os == NULL) + return NULL; + + gold_assert(this->eh_frame_section_ == os); + + elfcpp::Elf_Xword orig_flags = os->flags(); + + if (!parameters->incremental() + && this->eh_frame_data_->add_ehframe_input_section(object, + symbols, + symbols_size, + symbol_names, + symbol_names_size, + shndx, + reloc_shndx, + reloc_type)) + { + os->update_flags_for_input_section(shdr.get_sh_flags()); + + // A writable .eh_frame section is a RELRO section. + if ((orig_flags & (elfcpp::SHF_WRITE | elfcpp::SHF_EXECINSTR)) + != (os->flags() & (elfcpp::SHF_WRITE | elfcpp::SHF_EXECINSTR))) + { + os->set_is_relro(); + os->set_order(ORDER_RELRO); + } + + // We found a .eh_frame section we are going to optimize, so now + // we can add the set of optimized sections to the output + // section. We need to postpone adding this until we've found a + // section we can optimize so that the .eh_frame section in + // crtbegin.o winds up at the start of the output section. + if (!this->added_eh_frame_data_) + { + os->add_output_section_data(this->eh_frame_data_); + this->added_eh_frame_data_ = true; + } + *off = -1; + } + else + { + // We couldn't handle this .eh_frame section for some reason. + // Add it as a normal section. + bool saw_sections_clause = this->script_options_->saw_sections_clause(); + *off = os->add_input_section(this, object, shndx, ".eh_frame", shdr, + reloc_shndx, saw_sections_clause); + this->have_added_input_section_ = true; + + if ((orig_flags & (elfcpp::SHF_WRITE | elfcpp::SHF_EXECINSTR)) + != (os->flags() & (elfcpp::SHF_WRITE | elfcpp::SHF_EXECINSTR))) + os->set_order(this->default_section_order(os, false)); + } + + return os; +} + +// Create and return the magic .eh_frame section. Create +// .eh_frame_hdr also if appropriate. OBJECT is the object with the +// input .eh_frame section; it may be NULL. + +Output_section* +Layout::make_eh_frame_section(const Relobj* object) +{ + // FIXME: On x86_64, this could use SHT_X86_64_UNWIND rather than + // SHT_PROGBITS. + Output_section* os = this->choose_output_section(object, ".eh_frame", + elfcpp::SHT_PROGBITS, + elfcpp::SHF_ALLOC, false, + ORDER_EHFRAME, false); + if (os == NULL) + return NULL; + + if (this->eh_frame_section_ == NULL) + { + this->eh_frame_section_ = os; + this->eh_frame_data_ = new Eh_frame(); + + // For incremental linking, we do not optimize .eh_frame sections + // or create a .eh_frame_hdr section. + if (parameters->options().eh_frame_hdr() && !parameters->incremental()) + { + Output_section* hdr_os = + this->choose_output_section(NULL, ".eh_frame_hdr", + elfcpp::SHT_PROGBITS, + elfcpp::SHF_ALLOC, false, + ORDER_EHFRAME, false); + + if (hdr_os != NULL) + { + Eh_frame_hdr* hdr_posd = new Eh_frame_hdr(os, + this->eh_frame_data_); + hdr_os->add_output_section_data(hdr_posd); + + hdr_os->set_after_input_sections(); + + if (!this->script_options_->saw_phdrs_clause()) + { + Output_segment* hdr_oseg; + hdr_oseg = this->make_output_segment(elfcpp::PT_GNU_EH_FRAME, + elfcpp::PF_R); + hdr_oseg->add_output_section_to_nonload(hdr_os, + elfcpp::PF_R); + } + + this->eh_frame_data_->set_eh_frame_hdr(hdr_posd); + } + } + } + + return os; +} + +// Add an exception frame for a PLT. This is called from target code. + +void +Layout::add_eh_frame_for_plt(Output_data* plt, const unsigned char* cie_data, + size_t cie_length, const unsigned char* fde_data, + size_t fde_length) +{ + if (parameters->incremental()) + { + // FIXME: Maybe this could work some day.... + return; + } + Output_section* os = this->make_eh_frame_section(NULL); + if (os == NULL) + return; + this->eh_frame_data_->add_ehframe_for_plt(plt, cie_data, cie_length, + fde_data, fde_length); + if (!this->added_eh_frame_data_) + { + os->add_output_section_data(this->eh_frame_data_); + this->added_eh_frame_data_ = true; + } +} + +// Scan a .debug_info or .debug_types section, and add summary +// information to the .gdb_index section. + +template +void +Layout::add_to_gdb_index(bool is_type_unit, + Sized_relobj* object, + const unsigned char* symbols, + off_t symbols_size, + unsigned int shndx, + unsigned int reloc_shndx, + unsigned int reloc_type) +{ + if (this->gdb_index_data_ == NULL) + { + Output_section* os = this->choose_output_section(NULL, ".gdb_index", + elfcpp::SHT_PROGBITS, 0, + false, ORDER_INVALID, + false); + if (os == NULL) + return; + + this->gdb_index_data_ = new Gdb_index(os); + os->add_output_section_data(this->gdb_index_data_); + os->set_after_input_sections(); + } + + this->gdb_index_data_->scan_debug_info(is_type_unit, object, symbols, + symbols_size, shndx, reloc_shndx, + reloc_type); +} + +// Add POSD to an output section using NAME, TYPE, and FLAGS. Return +// the output section. + +Output_section* +Layout::add_output_section_data(const char* name, elfcpp::Elf_Word type, + elfcpp::Elf_Xword flags, + Output_section_data* posd, + Output_section_order order, bool is_relro) +{ + Output_section* os = this->choose_output_section(NULL, name, type, flags, + false, order, is_relro); + if (os != NULL) + os->add_output_section_data(posd); + return os; +} + +// Map section flags to segment flags. + +elfcpp::Elf_Word +Layout::section_flags_to_segment(elfcpp::Elf_Xword flags) +{ + elfcpp::Elf_Word ret = elfcpp::PF_R; + if ((flags & elfcpp::SHF_WRITE) != 0) + ret |= elfcpp::PF_W; + if ((flags & elfcpp::SHF_EXECINSTR) != 0) + ret |= elfcpp::PF_X; + return ret; +} + +// Make a new Output_section, and attach it to segments as +// appropriate. ORDER is the order in which this section should +// appear in the output segment. IS_RELRO is true if this is a relro +// (read-only after relocations) section. + +Output_section* +Layout::make_output_section(const char* name, elfcpp::Elf_Word type, + elfcpp::Elf_Xword flags, + Output_section_order order, bool is_relro) +{ + Output_section* os; + if ((flags & elfcpp::SHF_ALLOC) == 0 + && strcmp(parameters->options().compress_debug_sections(), "none") != 0 + && is_compressible_debug_section(name)) + 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) + { + os = this->debug_abbrev_ = new Output_reduced_debug_abbrev_section( + name, type, flags); + if (this->debug_info_) + 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) + { + os = this->debug_info_ = new Output_reduced_debug_info_section( + name, type, flags); + if (this->debug_abbrev_) + this->debug_info_->set_abbreviations(this->debug_abbrev_); + } + else + { + // Sometimes .init_array*, .preinit_array* and .fini_array* do + // not have correct section types. Force them here. + if (type == elfcpp::SHT_PROGBITS) + { + if (is_prefix_of(".init_array", name)) + type = elfcpp::SHT_INIT_ARRAY; + else if (is_prefix_of(".preinit_array", name)) + type = elfcpp::SHT_PREINIT_ARRAY; + else if (is_prefix_of(".fini_array", name)) + type = elfcpp::SHT_FINI_ARRAY; + } + + // FIXME: const_cast is ugly. + Target* target = const_cast(¶meters->target()); + os = target->make_output_section(name, type, flags); + } + + // With -z relro, we have to recognize the special sections by name. + // There is no other way. + bool is_relro_local = false; + if (!this->script_options_->saw_sections_clause() + && parameters->options().relro() + && (flags & elfcpp::SHF_ALLOC) != 0 + && (flags & elfcpp::SHF_WRITE) != 0) + { + if (type == elfcpp::SHT_PROGBITS) + { + if ((flags & elfcpp::SHF_TLS) != 0) + is_relro = true; + else if (strcmp(name, ".data.rel.ro") == 0) + is_relro = true; + else if (strcmp(name, ".data.rel.ro.local") == 0) + { + is_relro = true; + is_relro_local = true; + } + else if (strcmp(name, ".ctors") == 0 + || strcmp(name, ".dtors") == 0 + || strcmp(name, ".jcr") == 0) + is_relro = true; + } + else if (type == elfcpp::SHT_INIT_ARRAY + || type == elfcpp::SHT_FINI_ARRAY + || type == elfcpp::SHT_PREINIT_ARRAY) + is_relro = true; + } + + if (is_relro) + os->set_is_relro(); + + if (order == ORDER_INVALID && (flags & elfcpp::SHF_ALLOC) != 0) + order = this->default_section_order(os, is_relro_local); + + os->set_order(order); + + parameters->target().new_output_section(os); + + this->section_list_.push_back(os); + + // The GNU linker by default sorts some sections by priority, so we + // do the same. We need to know that this might happen before we + // attach any input sections. + if (!this->script_options_->saw_sections_clause() + && !parameters->options().relocatable() + && (strcmp(name, ".init_array") == 0 + || strcmp(name, ".fini_array") == 0 + || (!parameters->options().ctors_in_init_array() + && (strcmp(name, ".ctors") == 0 + || strcmp(name, ".dtors") == 0)))) + os->set_may_sort_attached_input_sections(); + + // The GNU linker by default sorts .text.{unlikely,exit,startup,hot} + // sections before other .text sections. We are compatible. We + // need to know that this might happen before we attach any input + // sections. + if (parameters->options().text_reorder() + && !this->script_options_->saw_sections_clause() + && !this->is_section_ordering_specified() + && !parameters->options().relocatable() + && strcmp(name, ".text") == 0) + os->set_may_sort_attached_input_sections(); + + // GNU linker sorts section by name with --sort-section=name. + if (strcmp(parameters->options().sort_section(), "name") == 0) + os->set_must_sort_attached_input_sections(); + + // Check for .stab*str sections, as .stab* sections need to link to + // them. + if (type == elfcpp::SHT_STRTAB + && !this->have_stabstr_section_ + && strncmp(name, ".stab", 5) == 0 + && strcmp(name + strlen(name) - 3, "str") == 0) + this->have_stabstr_section_ = true; + + // During a full incremental link, we add patch space to most + // PROGBITS and NOBITS sections. Flag those that may be + // arbitrarily padded. + if ((type == elfcpp::SHT_PROGBITS || type == elfcpp::SHT_NOBITS) + && order != ORDER_INTERP + && order != ORDER_INIT + && order != ORDER_PLT + && order != ORDER_FINI + && order != ORDER_RELRO_LAST + && order != ORDER_NON_RELRO_FIRST + && strcmp(name, ".eh_frame") != 0 + && strcmp(name, ".ctors") != 0 + && strcmp(name, ".dtors") != 0 + && strcmp(name, ".jcr") != 0) + { + os->set_is_patch_space_allowed(); + + // Certain sections require "holes" to be filled with + // specific fill patterns. These fill patterns may have + // 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)); + else if (strcmp(name, ".debug_types") == 0) + 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()); + } + + // 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(¶meters->target(), os); + + return os; +} + +// Return the default order in which a section should be placed in an +// output segment. This function captures a lot of the ideas in +// ld/scripttempl/elf.sc in the GNU linker. Note that the order of a +// linker created section is normally set when the section is created; +// this function is used for input sections. + +Output_section_order +Layout::default_section_order(Output_section* os, bool is_relro_local) +{ + gold_assert((os->flags() & elfcpp::SHF_ALLOC) != 0); + bool is_write = (os->flags() & elfcpp::SHF_WRITE) != 0; + bool is_execinstr = (os->flags() & elfcpp::SHF_EXECINSTR) != 0; + bool is_bss = false; + + switch (os->type()) + { + default: + case elfcpp::SHT_PROGBITS: + break; + case elfcpp::SHT_NOBITS: + is_bss = true; + break; + case elfcpp::SHT_RELA: + case elfcpp::SHT_REL: + if (!is_write) + return ORDER_DYNAMIC_RELOCS; + break; + case elfcpp::SHT_HASH: + case elfcpp::SHT_DYNAMIC: + case elfcpp::SHT_SHLIB: + case elfcpp::SHT_DYNSYM: + case elfcpp::SHT_GNU_HASH: + case elfcpp::SHT_GNU_verdef: + case elfcpp::SHT_GNU_verneed: + case elfcpp::SHT_GNU_versym: + if (!is_write) + return ORDER_DYNAMIC_LINKER; + break; + case elfcpp::SHT_NOTE: + return is_write ? ORDER_RW_NOTE : ORDER_RO_NOTE; + } + + if ((os->flags() & elfcpp::SHF_TLS) != 0) + return is_bss ? ORDER_TLS_BSS : ORDER_TLS_DATA; + + if (!is_bss && !is_write) + { + if (is_execinstr) + { + if (strcmp(os->name(), ".init") == 0) + return ORDER_INIT; + else if (strcmp(os->name(), ".fini") == 0) + return ORDER_FINI; + } + return is_execinstr ? ORDER_TEXT : ORDER_READONLY; + } + + if (os->is_relro()) + return is_relro_local ? ORDER_RELRO_LOCAL : ORDER_RELRO; + + if (os->is_small_section()) + return is_bss ? ORDER_SMALL_BSS : ORDER_SMALL_DATA; + if (os->is_large_section()) + return is_bss ? ORDER_LARGE_BSS : ORDER_LARGE_DATA; + + return is_bss ? ORDER_BSS : ORDER_DATA; +} + +// Attach output sections to segments. This is called after we have +// seen all the input sections. + +void +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(target, *p); + + this->sections_are_attached_ = true; +} + +// Attach an output section to a segment. + +void +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(target, os); +} + +// Attach an allocated output section to a segment. + +void +Layout::attach_allocated_section_to_segment(const Target* target, + Output_section* os) +{ + elfcpp::Elf_Xword flags = os->flags(); + gold_assert((flags & elfcpp::SHF_ALLOC) != 0); + + if (parameters->options().relocatable()) + return; + + // If we have a SECTIONS clause, we can't handle the attachment to + // segments until after we've seen all the sections. + if (this->script_options_->saw_sections_clause()) + return; + + gold_assert(!this->script_options_->saw_phdrs_clause()); + + // This output section goes into a PT_LOAD segment. + + elfcpp::Elf_Word seg_flags = Layout::section_flags_to_segment(flags); + + // If this output section's segment has extra flags that need to be set, + // coming from a linker plugin, do that. + seg_flags |= os->extra_segment_flags(); + + // Check for --section-start. + uint64_t addr; + bool is_address_set = parameters->options().section_start(os->name(), &addr); + + // In general the only thing we really care about for PT_LOAD + // segments is whether or not they are writable or executable, + // so that is how we search for them. + // Large data sections also go into their own PT_LOAD segment. + // People who need segments sorted on some other basis will + // have to use a linker script. + + Segment_list::const_iterator p; + if (!os->is_unique_segment()) + { + for (p = this->segment_list_.begin(); + p != this->segment_list_.end(); + ++p) + { + if ((*p)->type() != elfcpp::PT_LOAD) + continue; + if ((*p)->is_unique_segment()) + continue; + if (!parameters->options().omagic() + && ((*p)->flags() & elfcpp::PF_W) != (seg_flags & elfcpp::PF_W)) + continue; + if ((target->isolate_execinstr() || parameters->options().rosegment()) + && ((*p)->flags() & elfcpp::PF_X) != (seg_flags & elfcpp::PF_X)) + continue; + // If -Tbss was specified, we need to separate the data and BSS + // segments. + if (parameters->options().user_set_Tbss()) + { + if ((os->type() == elfcpp::SHT_NOBITS) + == (*p)->has_any_data_sections()) + continue; + } + if (os->is_large_data_section() && !(*p)->is_large_data_segment()) + continue; + + if (is_address_set) + { + if ((*p)->are_addresses_set()) + continue; + + (*p)->add_initial_output_data(os); + (*p)->update_flags_for_output_section(seg_flags); + (*p)->set_addresses(addr, addr); + break; + } + + (*p)->add_output_section_to_load(this, os, seg_flags); + break; + } + } + + if (p == this->segment_list_.end() + || os->is_unique_segment()) + { + Output_segment* oseg = this->make_output_segment(elfcpp::PT_LOAD, + seg_flags); + if (os->is_large_data_section()) + oseg->set_is_large_data_segment(); + oseg->add_output_section_to_load(this, os, seg_flags); + if (is_address_set) + oseg->set_addresses(addr, addr); + // Check if segment should be marked unique. For segments marked + // unique by linker plugins, set the new alignment if specified. + if (os->is_unique_segment()) + { + oseg->set_is_unique_segment(); + if (os->segment_alignment() != 0) + oseg->set_minimum_p_align(os->segment_alignment()); + } + } + + // If we see a loadable SHT_NOTE section, we create a PT_NOTE + // segment. + if (os->type() == elfcpp::SHT_NOTE) + { + // 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; + } + } + + 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); + } + } + + // If we see a loadable SHF_TLS section, we create a PT_TLS + // segment. There can only be one such segment. + if ((flags & elfcpp::SHF_TLS) != 0) + { + if (this->tls_segment_ == NULL) + this->make_output_segment(elfcpp::PT_TLS, seg_flags); + this->tls_segment_->add_output_section_to_nonload(os, seg_flags); + } + + // If -z relro is in effect, and we see a relro section, we create a + // PT_GNU_RELRO segment. There can only be one such segment. + if (os->is_relro() && parameters->options().relro()) + { + gold_assert(seg_flags == (elfcpp::PF_R | elfcpp::PF_W)); + if (this->relro_segment_ == NULL) + this->make_output_segment(elfcpp::PT_GNU_RELRO, seg_flags); + this->relro_segment_->add_output_section_to_nonload(os, seg_flags); + } + + // If we see a section named .interp, put it into a PT_INTERP + // segment. This seems broken to me, but this is what GNU ld does, + // and glibc expects it. + if (strcmp(os->name(), ".interp") == 0 + && !this->script_options_->saw_phdrs_clause()) + { + if (this->interp_segment_ == NULL) + this->make_output_segment(elfcpp::PT_INTERP, seg_flags); + else + gold_warning(_("multiple '.interp' sections in input files " + "may cause confusing PT_INTERP segment")); + this->interp_segment_->add_output_section_to_nonload(os, seg_flags); + } +} + +// Make an output section for a script. + +Output_section* +Layout::make_output_section_for_script( + const char* name, + Script_sections::Section_type section_type) +{ + name = this->namepool_.add(name, false, NULL); + elfcpp::Elf_Xword sh_flags = elfcpp::SHF_ALLOC; + if (section_type == Script_sections::ST_NOLOAD) + sh_flags = 0; + Output_section* os = this->make_output_section(name, elfcpp::SHT_PROGBITS, + sh_flags, ORDER_INVALID, + false); + os->set_found_in_sections_clause(); + if (section_type == Script_sections::ST_NOLOAD) + os->set_is_noload(); + return os; +} + +// Return the number of segments we expect to see. + +size_t +Layout::expected_segment_count() const +{ + size_t ret = this->segment_list_.size(); + + // If we didn't see a SECTIONS clause in a linker script, we should + // already have the complete list of segments. Otherwise we ask the + // SECTIONS clause how many segments it expects, and add in the ones + // we already have (PT_GNU_STACK, PT_GNU_EH_FRAME, etc.) + + if (!this->script_options_->saw_sections_clause()) + return ret; + else + { + const Script_sections* ss = this->script_options_->script_sections(); + return ret + ss->expected_segment_count(this); + } +} + +// Handle the .note.GNU-stack section at layout time. SEEN_GNU_STACK +// is whether we saw a .note.GNU-stack section in the object file. +// GNU_STACK_FLAGS is the section flags. The flags give the +// protection required for stack memory. We record this in an +// executable as a PT_GNU_STACK segment. If an object file does not +// have a .note.GNU-stack segment, we must assume that it is an old +// object. On some targets that will force an executable stack. + +void +Layout::layout_gnu_stack(bool seen_gnu_stack, uint64_t gnu_stack_flags, + const Object* obj) +{ + if (!seen_gnu_stack) + { + this->input_without_gnu_stack_note_ = true; + if (parameters->options().warn_execstack() + && parameters->target().is_default_stack_executable()) + gold_warning(_("%s: missing .note.GNU-stack section" + " implies executable stack"), + obj->name().c_str()); + } + else + { + this->input_with_gnu_stack_note_ = true; + if ((gnu_stack_flags & elfcpp::SHF_EXECINSTR) != 0) + { + this->input_requires_executable_stack_ = true; + if (parameters->options().warn_execstack() + || parameters->options().is_stack_executable()) + gold_warning(_("%s: requires executable stack"), + obj->name().c_str()); + } + } +} + +// Create automatic note sections. + +void +Layout::create_notes() +{ + this->create_gold_note(); + this->create_executable_stack_info(); + this->create_build_id(); +} + +// Create the dynamic sections which are needed before we read the +// relocs. + +void +Layout::create_initial_dynamic_sections(Symbol_table* symtab) +{ + if (parameters->doing_static_link()) + return; + + this->dynamic_section_ = this->choose_output_section(NULL, ".dynamic", + elfcpp::SHT_DYNAMIC, + (elfcpp::SHF_ALLOC + | elfcpp::SHF_WRITE), + false, ORDER_RELRO, + true); + + // A linker script may discard .dynamic, so check for NULL. + if (this->dynamic_section_ != NULL) + { + this->dynamic_symbol_ = + symtab->define_in_output_data("_DYNAMIC", NULL, + Symbol_table::PREDEFINED, + this->dynamic_section_, 0, 0, + elfcpp::STT_OBJECT, elfcpp::STB_LOCAL, + elfcpp::STV_HIDDEN, 0, false, false); + + this->dynamic_data_ = new Output_data_dynamic(&this->dynpool_); + + this->dynamic_section_->add_output_section_data(this->dynamic_data_); + } +} + +// For each output section whose name can be represented as C symbol, +// define __start and __stop symbols for the section. This is a GNU +// extension. + +void +Layout::define_section_symbols(Symbol_table* symtab) +{ + for (Section_list::const_iterator p = this->section_list_.begin(); + p != this->section_list_.end(); + ++p) + { + const char* const name = (*p)->name(); + if (is_cident(name)) + { + const std::string name_string(name); + const std::string start_name(cident_section_start_prefix + + name_string); + const std::string stop_name(cident_section_stop_prefix + + name_string); + + symtab->define_in_output_data(start_name.c_str(), + NULL, // version + Symbol_table::PREDEFINED, + *p, + 0, // value + 0, // symsize + elfcpp::STT_NOTYPE, + elfcpp::STB_GLOBAL, + elfcpp::STV_DEFAULT, + 0, // nonvis + false, // offset_is_from_end + true); // only_if_ref + + symtab->define_in_output_data(stop_name.c_str(), + NULL, // version + Symbol_table::PREDEFINED, + *p, + 0, // value + 0, // symsize + elfcpp::STT_NOTYPE, + elfcpp::STB_GLOBAL, + elfcpp::STV_DEFAULT, + 0, // nonvis + true, // offset_is_from_end + true); // only_if_ref + } + } +} + +// Define symbols for group signatures. + +void +Layout::define_group_signatures(Symbol_table* symtab) +{ + for (Group_signatures::iterator p = this->group_signatures_.begin(); + p != this->group_signatures_.end(); + ++p) + { + Symbol* sym = symtab->lookup(p->signature, NULL); + if (sym != NULL) + p->section->set_info_symndx(sym); + else + { + // Force the name of the group section to the group + // signature, and use the group's section symbol as the + // signature symbol. + if (strcmp(p->section->name(), p->signature) != 0) + { + const char* name = this->namepool_.add(p->signature, + true, NULL); + p->section->set_name(name); + } + p->section->set_needs_symtab_index(); + p->section->set_info_section_symndx(p->section); + } + } + + this->group_signatures_.clear(); +} + +// Find the first read-only PT_LOAD segment, creating one if +// necessary. + +Output_segment* +Layout::find_first_load_seg(const Target* target) +{ + Output_segment* best = NULL; + for (Segment_list::const_iterator p = this->segment_list_.begin(); + p != this->segment_list_.end(); + ++p) + { + if ((*p)->type() == elfcpp::PT_LOAD + && ((*p)->flags() & elfcpp::PF_R) != 0 + && (parameters->options().omagic() + || ((*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; + + gold_assert(!this->script_options_->saw_phdrs_clause()); + + Output_segment* load_seg = this->make_output_segment(elfcpp::PT_LOAD, + elfcpp::PF_R); + return load_seg; +} + +// Save states of all current output segments. Store saved states +// in SEGMENT_STATES. + +void +Layout::save_segments(Segment_states* segment_states) +{ + for (Segment_list::const_iterator p = this->segment_list_.begin(); + p != this->segment_list_.end(); + ++p) + { + Output_segment* segment = *p; + // Shallow copy. + Output_segment* copy = new Output_segment(*segment); + (*segment_states)[segment] = copy; + } +} + +// Restore states of output segments and delete any segment not found in +// SEGMENT_STATES. + +void +Layout::restore_segments(const Segment_states* segment_states) +{ + // Go through the segment list and remove any segment added in the + // relaxation loop. + this->tls_segment_ = NULL; + this->relro_segment_ = NULL; + Segment_list::iterator list_iter = this->segment_list_.begin(); + while (list_iter != this->segment_list_.end()) + { + Output_segment* segment = *list_iter; + Segment_states::const_iterator states_iter = + segment_states->find(segment); + if (states_iter != segment_states->end()) + { + const Output_segment* copy = states_iter->second; + // Shallow copy to restore states. + *segment = *copy; + + // Also fix up TLS and RELRO segment pointers as appropriate. + if (segment->type() == elfcpp::PT_TLS) + this->tls_segment_ = segment; + else if (segment->type() == elfcpp::PT_GNU_RELRO) + this->relro_segment_ = segment; + + ++list_iter; + } + else + { + 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; + } + } +} + +// Clean up after relaxation so that sections can be laid out again. + +void +Layout::clean_up_after_relaxation() +{ + // Restore the segments to point state just prior to the relaxation loop. + Script_sections* script_section = this->script_options_->script_sections(); + script_section->release_segments(); + this->restore_segments(this->segment_states_); + + // Reset section addresses and file offsets + for (Section_list::iterator p = this->section_list_.begin(); + p != this->section_list_.end(); + ++p) + { + (*p)->restore_states(); + + // If an input section changes size because of relaxation, + // we need to adjust the section offsets of all input sections. + // after such a section. + if ((*p)->section_offsets_need_adjustment()) + (*p)->adjust_section_offsets(); + + (*p)->reset_address_and_file_offset(); + } + + // Reset special output object address and file offsets. + for (Data_list::iterator p = this->special_output_list_.begin(); + p != this->special_output_list_.end(); + ++p) + (*p)->reset_address_and_file_offset(); + + // A linker script may have created some output section data objects. + // They are useless now. + for (Output_section_data_list::const_iterator p = + this->script_output_section_data_list_.begin(); + p != this->script_output_section_data_list_.end(); + ++p) + delete *p; + this->script_output_section_data_list_.clear(); + + // Special-case fill output objects are recreated each time through + // the relaxation loop. + this->reset_relax_output(); +} + +void +Layout::reset_relax_output() +{ + for (Data_list::const_iterator p = this->relax_output_list_.begin(); + p != this->relax_output_list_.end(); + ++p) + delete *p; + this->relax_output_list_.clear(); +} + +// Prepare for relaxation. + +void +Layout::prepare_for_relaxation() +{ + // Create an relaxation debug check if in debugging mode. + if (is_debugging_enabled(DEBUG_RELAXATION)) + this->relaxation_debug_check_ = new Relaxation_debug_check(); + + // Save segment states. + this->segment_states_ = new Segment_states(); + this->save_segments(this->segment_states_); + + for(Section_list::const_iterator p = this->section_list_.begin(); + p != this->section_list_.end(); + ++p) + (*p)->save_states(); + + if (is_debugging_enabled(DEBUG_RELAXATION)) + this->relaxation_debug_check_->check_output_data_for_reset_values( + this->section_list_, this->special_output_list_, + this->relax_output_list_); + + // Also enable recording of output section data from scripts. + this->record_output_section_data_from_script_ = true; +} + +// If the user set the address of the text segment, that may not be +// compatible with putting the segment headers and file headers into +// that segment. For isolate_execinstr() targets, it's the rodata +// segment rather than text where we might put the headers. +static inline bool +load_seg_unusable_for_headers(const Target* target) +{ + const General_options& options = parameters->options(); + if (target->isolate_execinstr()) + return (options.user_set_Trodata_segment() + && options.Trodata_segment() % target->abi_pagesize() != 0); + else + return (options.user_set_Ttext() + && options.Ttext() % target->abi_pagesize() != 0); +} + +// 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. +// +// The number of segments created by a linking script without a PHDRS +// clause may be affected by section sizes and alignments. There is +// a remote chance that relaxation causes different number of PT_LOAD +// segments are created and sections are attached to different segments. +// Therefore, we always throw away all segments created during section +// 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. +// 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. +// SEGMENT_HEADERS points to the output segment header. +// FILE_HEADER points to the output file header. +// PSHNDX is the address to store the output section index. + +off_t inline +Layout::relaxation_loop_body( + int pass, + Target* target, + Symbol_table* symtab, + Output_segment** pload_seg, + Output_segment* phdr_seg, + Output_segment_headers* segment_headers, + Output_file_header* file_header, + unsigned int* pshndx) +{ + // If this is not the first iteration, we need to clean up after + // relaxation so that we can lay out the sections again. + if (pass != 0) + this->clean_up_after_relaxation(); + + // If there is a SECTIONS clause, put all the input sections into + // the required order. + Output_segment* load_seg; + if (this->script_options_->saw_sections_clause()) + load_seg = this->set_section_addresses_from_script(symtab); + else if (parameters->options().relocatable()) + load_seg = NULL; + else + load_seg = this->find_first_load_seg(target); + + if (parameters->options().oformat_enum() + != General_options::OBJECT_FORMAT_ELF) + load_seg = NULL; + + if (load_seg_unusable_for_headers(target)) + { + load_seg = NULL; + phdr_seg = NULL; + } + + gold_assert(phdr_seg == NULL + || load_seg != NULL + || this->script_options_->saw_sections_clause()); + + // If the address of the load segment we found has been set by + // --section-start rather than by a script, then adjust the VMA and + // LMA downward if possible to include the file and section headers. + uint64_t header_gap = 0; + if (load_seg != NULL + && load_seg->are_addresses_set() + && !this->script_options_->saw_sections_clause() + && !parameters->options().relocatable()) + { + file_header->finalize_data_size(); + segment_headers->finalize_data_size(); + size_t sizeof_headers = (file_header->data_size() + + segment_headers->data_size()); + const uint64_t abi_pagesize = target->abi_pagesize(); + uint64_t hdr_paddr = load_seg->paddr() - sizeof_headers; + hdr_paddr &= ~(abi_pagesize - 1); + uint64_t subtract = load_seg->paddr() - hdr_paddr; + if (load_seg->paddr() < subtract || load_seg->vaddr() < subtract) + load_seg = NULL; + else + { + load_seg->set_addresses(load_seg->vaddr() - subtract, + load_seg->paddr() - subtract); + header_gap = subtract - sizeof_headers; + } + } + + // Lay out the segment headers. + if (!parameters->options().relocatable()) + { + gold_assert(segment_headers != NULL); + if (header_gap != 0 && load_seg != NULL) + { + Output_data_zero_fill* z = new Output_data_zero_fill(header_gap, 1); + load_seg->add_initial_output_data(z); + } + if (load_seg != NULL) + load_seg->add_initial_output_data(segment_headers); + if (phdr_seg != NULL) + phdr_seg->add_initial_output_data(segment_headers); + } + + // Lay out the file header. + if (load_seg != NULL) + load_seg->add_initial_output_data(file_header); + + if (this->script_options_->saw_phdrs_clause() + && !parameters->options().relocatable()) + { + // Support use of FILEHDRS and PHDRS attachments in a PHDRS + // clause in a linker script. + Script_sections* ss = this->script_options_->script_sections(); + ss->put_headers_in_phdrs(file_header, segment_headers); + } + + // We set the output section indexes in set_segment_offsets and + // set_section_indexes. + *pshndx = 1; + + // Set the file offsets of all the segments, and all the sections + // they contain. + off_t off; + if (!parameters->options().relocatable()) + off = this->set_segment_offsets(target, load_seg, pshndx); + else + off = this->set_relocatable_section_offsets(file_header, pshndx); + + // Verify that the dummy relaxation does not change anything. + if (is_debugging_enabled(DEBUG_RELAXATION)) + { + if (pass == 0) + this->relaxation_debug_check_->read_sections(this->section_list_); + else + this->relaxation_debug_check_->verify_sections(this->section_list_); + } + + *pload_seg = load_seg; + return off; +} + +// Search the list of patterns and find the postion of the given section +// name in the output section. If the section name matches a glob +// pattern and a non-glob name, then the non-glob position takes +// precedence. Return 0 if no match is found. + +unsigned int +Layout::find_section_order_index(const std::string& section_name) +{ + Unordered_map::iterator map_it; + map_it = this->input_section_position_.find(section_name); + if (map_it != this->input_section_position_.end()) + return map_it->second; + + // Absolute match failed. Linear search the glob patterns. + std::vector::iterator it; + for (it = this->input_section_glob_.begin(); + it != this->input_section_glob_.end(); + ++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; + } + } + return 0; +} + +// Read the sequence of input sections from the file specified with +// option --section-ordering-file. + +void +Layout::read_layout_from_file() +{ + const char* filename = parameters->options().section_ordering_file(); + std::ifstream in; + std::string line; + + in.open(filename); + if (!in) + gold_fatal(_("unable to open --section-ordering-file file %s: %s"), + filename, strerror(errno)); + + std::getline(in, line); // this chops off the trailing \n, if any + unsigned int position = 1; + this->set_section_ordering_specified(); + + while (in) + { + if (!line.empty() && line[line.length() - 1] == '\r') // Windows + line.resize(line.length() - 1); + // Ignore comments, beginning with '#' + if (line[0] == '#') + { + 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); + position++; + std::getline(in, line); + } +} + +// Finalize the layout. When this is called, we have created all the +// output sections and all the output segments which are based on +// input sections. We have several things to do, and we have to do +// them in the right order, so that we get the right results correctly +// and efficiently. + +// 1) Finalize the list of output segments and create the segment +// table header. + +// 2) Finalize the dynamic symbol table and associated sections. + +// 3) Determine the final file offset of all the output segments. + +// 4) Determine the final file offset of all the SHF_ALLOC output +// sections. + +// 5) Create the symbol table sections and the section name table +// section. + +// 6) Finalize the symbol table: set symbol values to their final +// value and make a final determination of which symbols are going +// into the output symbol table. + +// 7) Create the section table header. + +// 8) Determine the final file offset of all the output sections which +// are not SHF_ALLOC, including the section table header. + +// 9) Finalize the ELF file header. + +// This function returns the size of the output file. + +off_t +Layout::finalize(const Input_objects* input_objects, Symbol_table* symtab, + Target* target, const Task* task) +{ + target->finalize_sections(this, input_objects, symtab); + + this->count_local_symbols(task, input_objects); + + this->link_stabs_sections(); + + Output_segment* phdr_seg = NULL; + if (!parameters->options().relocatable() && !parameters->doing_static_link()) + { + // There was a dynamic object in the link. We need to create + // some information for the dynamic linker. + + // Create the PT_PHDR segment which will hold the program + // headers. + if (!this->script_options_->saw_phdrs_clause()) + phdr_seg = this->make_output_segment(elfcpp::PT_PHDR, elfcpp::PF_R); + + // Create the dynamic symbol table, including the hash table. + Output_section* dynstr; + std::vector dynamic_symbols; + unsigned int local_dynamic_count; + Versions versions(*this->script_options()->version_script_info(), + &this->dynpool_); + this->create_dynamic_symtab(input_objects, symtab, &dynstr, + &local_dynamic_count, &dynamic_symbols, + &versions); + + // Create the .interp section to hold the name of the + // interpreter, and put it in a PT_INTERP segment. Don't do it + // if we saw a .interp section in an input file. + if ((!parameters->options().shared() + || parameters->options().dynamic_linker() != NULL) + && this->interp_segment_ == NULL) + this->create_interp(target); + + // Finish the .dynamic section to hold the dynamic data, and put + // it in a PT_DYNAMIC segment. + this->finish_dynamic_section(input_objects, symtab); + + // We should have added everything we need to the dynamic string + // table. + this->dynpool_.set_string_offsets(); + + // Create the version sections. We can't do this until the + // dynamic string table is complete. + this->create_version_sections(&versions, symtab, local_dynamic_count, + dynamic_symbols, dynstr); + + // Set the size of the _DYNAMIC symbol. We can't do this until + // after we call create_version_sections. + this->set_dynamic_symbol_size(symtab); + } + + // Create segment headers. + Output_segment_headers* segment_headers = + (parameters->options().relocatable() + ? NULL + : new Output_segment_headers(this->segment_list_)); + + // Lay out the file header. + Output_file_header* file_header = new Output_file_header(target, symtab, + segment_headers); + + this->special_output_list_.push_back(file_header); + if (segment_headers != NULL) + this->special_output_list_.push_back(segment_headers); + + // Find approriate places for orphan output sections if we are using + // 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; + int pass = 0; + + // 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 + { + off = this->relaxation_loop_body(pass, target, symtab, &load_seg, + phdr_seg, segment_headers, file_header, + &shndx); + pass++; + } + while (target->may_relax() + && target->relax(pass, input_objects, symtab, this, task)); + + // If there is a load segment that contains the file and program headers, + // provide a symbol __ehdr_start pointing there. + // A program can use this to examine itself robustly. + if (load_seg != NULL) + symtab->define_in_output_segment("__ehdr_start", NULL, + Symbol_table::PREDEFINED, load_seg, 0, 0, + elfcpp::STT_NOTYPE, elfcpp::STB_GLOBAL, + elfcpp::STV_HIDDEN, 0, + Symbol::SEGMENT_START, true); + + // Set the file offsets of all the non-data sections we've seen so + // far which don't have to wait for the input sections. We need + // this in order to finalize local symbols in non-allocated + // sections. + off = this->set_section_offsets(off, BEFORE_INPUT_SECTIONS_PASS); + + // Set the section indexes of all unallocated sections seen so far, + // in case any of them are somehow referenced by a symbol. + shndx = this->set_section_indexes(shndx); + + // Create the symbol table sections. + this->create_symtab_sections(input_objects, symtab, shndx, &off); + if (!parameters->doing_static_link()) + this->assign_local_dynsym_offsets(input_objects); + + // Process any symbol assignments from a linker script. This must + // be called after the symbol table has been finalized. + this->script_options_->finalize_symbols(symtab, this); + + // Create the incremental inputs sections. + if (this->incremental_inputs_) + { + this->incremental_inputs_->finalize(); + this->create_incremental_info_sections(symtab); + } + + // Create the .shstrtab section. + Output_section* shstrtab_section = this->create_shstrtab(); + + // Set the file offsets of the rest of the non-data sections which + // don't have to wait for the input sections. + off = this->set_section_offsets(off, BEFORE_INPUT_SECTIONS_PASS); + + // Now that all sections have been created, set the section indexes + // for any sections which haven't been done yet. + shndx = this->set_section_indexes(shndx); + + // Create the section table header. + this->create_shdrs(shstrtab_section, &off); + + // If there are no sections which require postprocessing, we can + // handle the section names now, and avoid a resize later. + if (!this->any_postprocessing_sections_) + { + off = this->set_section_offsets(off, + POSTPROCESSING_SECTIONS_PASS); + off = + this->set_section_offsets(off, + STRTAB_AFTER_POSTPROCESSING_SECTIONS_PASS); + } + + file_header->set_section_info(this->section_headers_, shstrtab_section); + + // Now we know exactly where everything goes in the output file + // (except for non-allocated sections which require postprocessing). + Output_data::layout_complete(); + + this->output_file_size_ = off; + + return off; +} + +// Create a note header following the format defined in the ELF ABI. +// NAME is the name, NOTE_TYPE is the type, SECTION_NAME is the name +// of the section to create, DESCSZ is the size of the descriptor. +// ALLOCATE is true if the section should be allocated in memory. +// This returns the new note section. It sets *TRAILING_PADDING to +// the number of trailing zero bytes required. + +Output_section* +Layout::create_note(const char* name, int note_type, + const char* section_name, size_t descsz, + bool allocate, size_t* trailing_padding) +{ + // Authorities all agree that the values in a .note field should + // be aligned on 4-byte boundaries for 32-bit binaries. However, + // they differ on what the alignment is for 64-bit binaries. + // The GABI says unambiguously they take 8-byte alignment: + // http://sco.com/developers/gabi/latest/ch5.pheader.html#note_section + // Other documentation says alignment should always be 4 bytes: + // http://www.netbsd.org/docs/kernel/elf-notes.html#note-format + // GNU ld and GNU readelf both support the latter (at least as of + // version 2.16.91), and glibc always generates the latter for + // .note.ABI-tag (as of version 1.6), so that's the one we go with + // here. +#ifdef GABI_FORMAT_FOR_DOTNOTE_SECTION // This is not defined by default. + const int size = parameters->target().get_size(); +#else + const int size = 32; +#endif + + // The contents of the .note section. + size_t namesz = strlen(name) + 1; + size_t aligned_namesz = align_address(namesz, size / 8); + size_t aligned_descsz = align_address(descsz, size / 8); + + size_t notehdrsz = 3 * (size / 8) + aligned_namesz; + + unsigned char* buffer = new unsigned char[notehdrsz]; + memset(buffer, 0, notehdrsz); + + bool is_big_endian = parameters->target().is_big_endian(); + + if (size == 32) + { + if (!is_big_endian) + { + elfcpp::Swap<32, false>::writeval(buffer, namesz); + elfcpp::Swap<32, false>::writeval(buffer + 4, descsz); + elfcpp::Swap<32, false>::writeval(buffer + 8, note_type); + } + else + { + elfcpp::Swap<32, true>::writeval(buffer, namesz); + elfcpp::Swap<32, true>::writeval(buffer + 4, descsz); + elfcpp::Swap<32, true>::writeval(buffer + 8, note_type); + } + } + else if (size == 64) + { + if (!is_big_endian) + { + elfcpp::Swap<64, false>::writeval(buffer, namesz); + elfcpp::Swap<64, false>::writeval(buffer + 8, descsz); + elfcpp::Swap<64, false>::writeval(buffer + 16, note_type); + } + else + { + elfcpp::Swap<64, true>::writeval(buffer, namesz); + elfcpp::Swap<64, true>::writeval(buffer + 8, descsz); + elfcpp::Swap<64, true>::writeval(buffer + 16, note_type); + } + } + else + gold_unreachable(); + + memcpy(buffer + 3 * (size / 8), name, namesz); + + elfcpp::Elf_Xword flags = 0; + Output_section_order order = ORDER_INVALID; + if (allocate) + { + flags = elfcpp::SHF_ALLOC; + order = ORDER_RO_NOTE; + } + Output_section* os = this->choose_output_section(NULL, section_name, + elfcpp::SHT_NOTE, + flags, false, order, false); + if (os == NULL) + return NULL; + + Output_section_data* posd = new Output_data_const_buffer(buffer, notehdrsz, + size / 8, + "** note header"); + os->add_output_section_data(posd); + + *trailing_padding = aligned_descsz - descsz; + + return os; +} + +// For an executable or shared library, create a note to record the +// version of gold used to create the binary. + +void +Layout::create_gold_note() +{ + if (parameters->options().relocatable() + || parameters->incremental_update()) + return; + + std::string desc = std::string("gold ") + gold::get_version_string(); + + size_t trailing_padding; + Output_section* os = this->create_note("GNU", elfcpp::NT_GNU_GOLD_VERSION, + ".note.gnu.gold-version", desc.size(), + false, &trailing_padding); + if (os == NULL) + return; + + Output_section_data* posd = new Output_data_const(desc, 4); + os->add_output_section_data(posd); + + if (trailing_padding > 0) + { + posd = new Output_data_zero_fill(trailing_padding, 0); + os->add_output_section_data(posd); + } +} + +// Record whether the stack should be executable. This can be set +// from the command line using the -z execstack or -z noexecstack +// options. Otherwise, if any input file has a .note.GNU-stack +// section with the SHF_EXECINSTR flag set, the stack should be +// executable. Otherwise, if at least one input file a +// .note.GNU-stack section, and some input file has no .note.GNU-stack +// section, we use the target default for whether the stack should be +// executable. Otherwise, we don't generate a stack note. When +// generating a object file, we create a .note.GNU-stack section with +// the appropriate marking. When generating an executable or shared +// library, we create a PT_GNU_STACK segment. + +void +Layout::create_executable_stack_info() +{ + bool is_stack_executable; + if (parameters->options().is_execstack_set()) + is_stack_executable = parameters->options().is_stack_executable(); + else if (!this->input_with_gnu_stack_note_) + return; + else + { + if (this->input_requires_executable_stack_) + is_stack_executable = true; + else if (this->input_without_gnu_stack_note_) + is_stack_executable = + parameters->target().is_default_stack_executable(); + else + is_stack_executable = false; + } + + if (parameters->options().relocatable()) + { + const char* name = this->namepool_.add(".note.GNU-stack", false, NULL); + elfcpp::Elf_Xword flags = 0; + if (is_stack_executable) + flags |= elfcpp::SHF_EXECINSTR; + this->make_output_section(name, elfcpp::SHT_PROGBITS, flags, + ORDER_INVALID, false); + } + else + { + if (this->script_options_->saw_phdrs_clause()) + return; + int flags = elfcpp::PF_R | elfcpp::PF_W; + if (is_stack_executable) + flags |= elfcpp::PF_X; + this->make_output_segment(elfcpp::PT_GNU_STACK, flags); + } +} + +// If --build-id was used, set up the build ID note. + +void +Layout::create_build_id() +{ + if (!parameters->options().user_set_build_id()) + return; + + const char* style = parameters->options().build_id(); + if (strcmp(style, "none") == 0) + return; + + // Set DESCSZ to the size of the note descriptor. When possible, + // set DESC to the note descriptor contents. + size_t descsz; + std::string desc; + if (strcmp(style, "md5") == 0) + descsz = 128 / 8; + else if ((strcmp(style, "sha1") == 0) || (strcmp(style, "tree") == 0)) + descsz = 160 / 8; + else if (strcmp(style, "uuid") == 0) + { + const size_t uuidsz = 128 / 8; + + char buffer[uuidsz]; + memset(buffer, 0, uuidsz); + + int descriptor = open_descriptor(-1, "/dev/urandom", O_RDONLY); + if (descriptor < 0) + gold_error(_("--build-id=uuid failed: could not open /dev/urandom: %s"), + strerror(errno)); + else + { + ssize_t got = ::read(descriptor, buffer, uuidsz); + release_descriptor(descriptor, true); + if (got < 0) + gold_error(_("/dev/urandom: read failed: %s"), strerror(errno)); + else if (static_cast(got) != uuidsz) + gold_error(_("/dev/urandom: expected %zu bytes, got %zd bytes"), + uuidsz, got); + } + + desc.assign(buffer, uuidsz); + descsz = uuidsz; + } + else if (strncmp(style, "0x", 2) == 0) + { + hex_init(); + const char* p = style + 2; + while (*p != '\0') + { + if (hex_p(p[0]) && hex_p(p[1])) + { + char c = (hex_value(p[0]) << 4) | hex_value(p[1]); + desc += c; + p += 2; + } + else if (*p == '-' || *p == ':') + ++p; + else + gold_fatal(_("--build-id argument '%s' not a valid hex number"), + style); + } + descsz = desc.size(); + } + else + gold_fatal(_("unrecognized --build-id argument '%s'"), style); + + // Create the note. + size_t trailing_padding; + Output_section* os = this->create_note("GNU", elfcpp::NT_GNU_BUILD_ID, + ".note.gnu.build-id", descsz, true, + &trailing_padding); + if (os == NULL) + return; + + if (!desc.empty()) + { + // We know the value already, so we fill it in now. + gold_assert(desc.size() == descsz); + + Output_section_data* posd = new Output_data_const(desc, 4); + os->add_output_section_data(posd); + + if (trailing_padding != 0) + { + posd = new Output_data_zero_fill(trailing_padding, 0); + os->add_output_section_data(posd); + } + } + else + { + // We need to compute a checksum after we have completed the + // link. + gold_assert(trailing_padding == 0); + this->build_id_note_ = new Output_data_zero_fill(descsz, 4); + os->add_output_section_data(this->build_id_note_); + } +} + +// If we have both .stabXX and .stabXXstr sections, then the sh_link +// field of the former should point to the latter. I'm not sure who +// started this, but the GNU linker does it, and some tools depend +// upon it. + +void +Layout::link_stabs_sections() +{ + if (!this->have_stabstr_section_) + return; + + for (Section_list::iterator p = this->section_list_.begin(); + p != this->section_list_.end(); + ++p) + { + if ((*p)->type() != elfcpp::SHT_STRTAB) + continue; + + const char* name = (*p)->name(); + if (strncmp(name, ".stab", 5) != 0) + continue; + + size_t len = strlen(name); + if (strcmp(name + len - 3, "str") != 0) + continue; + + std::string stab_name(name, len - 3); + Output_section* stab_sec; + stab_sec = this->find_output_section(stab_name.c_str()); + if (stab_sec != NULL) + stab_sec->set_link_section(*p); + } +} + +// Create .gnu_incremental_inputs and related sections needed +// for the next run of incremental linking to check what has changed. + +void +Layout::create_incremental_info_sections(Symbol_table* symtab) +{ + Incremental_inputs* incr = this->incremental_inputs_; + + gold_assert(incr != NULL); + + // Create the .gnu_incremental_inputs, _symtab, and _relocs input sections. + incr->create_data_sections(symtab); + + // Add the .gnu_incremental_inputs section. + const char* incremental_inputs_name = + this->namepool_.add(".gnu_incremental_inputs", false, NULL); + Output_section* incremental_inputs_os = + this->make_output_section(incremental_inputs_name, + elfcpp::SHT_GNU_INCREMENTAL_INPUTS, 0, + ORDER_INVALID, false); + incremental_inputs_os->add_output_section_data(incr->inputs_section()); + + // Add the .gnu_incremental_symtab section. + const char* incremental_symtab_name = + this->namepool_.add(".gnu_incremental_symtab", false, NULL); + Output_section* incremental_symtab_os = + this->make_output_section(incremental_symtab_name, + elfcpp::SHT_GNU_INCREMENTAL_SYMTAB, 0, + ORDER_INVALID, false); + incremental_symtab_os->add_output_section_data(incr->symtab_section()); + incremental_symtab_os->set_entsize(4); + + // Add the .gnu_incremental_relocs section. + const char* incremental_relocs_name = + this->namepool_.add(".gnu_incremental_relocs", false, NULL); + Output_section* incremental_relocs_os = + this->make_output_section(incremental_relocs_name, + elfcpp::SHT_GNU_INCREMENTAL_RELOCS, 0, + ORDER_INVALID, false); + incremental_relocs_os->add_output_section_data(incr->relocs_section()); + incremental_relocs_os->set_entsize(incr->relocs_entsize()); + + // Add the .gnu_incremental_got_plt section. + const char* incremental_got_plt_name = + this->namepool_.add(".gnu_incremental_got_plt", false, NULL); + Output_section* incremental_got_plt_os = + this->make_output_section(incremental_got_plt_name, + elfcpp::SHT_GNU_INCREMENTAL_GOT_PLT, 0, + ORDER_INVALID, false); + incremental_got_plt_os->add_output_section_data(incr->got_plt_section()); + + // Add the .gnu_incremental_strtab section. + 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); + Output_data_strtab* strtab_data = + new Output_data_strtab(incr->get_stringpool()); + incremental_strtab_os->add_output_section_data(strtab_data); + + incremental_inputs_os->set_after_input_sections(); + incremental_symtab_os->set_after_input_sections(); + incremental_relocs_os->set_after_input_sections(); + incremental_got_plt_os->set_after_input_sections(); + + incremental_inputs_os->set_link_section(incremental_strtab_os); + incremental_symtab_os->set_link_section(incremental_inputs_os); + incremental_relocs_os->set_link_section(incremental_inputs_os); + incremental_got_plt_os->set_link_section(incremental_inputs_os); +} + +// Return whether SEG1 should be before SEG2 in the output file. This +// is based entirely on the segment type and flags. When this is +// called the segment addresses have normally not yet been set. + +bool +Layout::segment_precedes(const Output_segment* seg1, + const Output_segment* seg2) +{ + elfcpp::Elf_Word type1 = seg1->type(); + elfcpp::Elf_Word type2 = seg2->type(); + + // The single PT_PHDR segment is required to precede any loadable + // segment. We simply make it always first. + if (type1 == elfcpp::PT_PHDR) + { + gold_assert(type2 != elfcpp::PT_PHDR); + return true; + } + if (type2 == elfcpp::PT_PHDR) + return false; + + // The single PT_INTERP segment is required to precede any loadable + // segment. We simply make it always second. + if (type1 == elfcpp::PT_INTERP) + { + gold_assert(type2 != elfcpp::PT_INTERP); + return true; + } + if (type2 == elfcpp::PT_INTERP) + return false; + + // We then put PT_LOAD segments before any other segments. + if (type1 == elfcpp::PT_LOAD && type2 != elfcpp::PT_LOAD) + return true; + if (type2 == elfcpp::PT_LOAD && type1 != elfcpp::PT_LOAD) + return false; + + // We put the PT_TLS segment last except for the PT_GNU_RELRO + // segment, because that is where the dynamic linker expects to find + // it (this is just for efficiency; other positions would also work + // correctly). + if (type1 == elfcpp::PT_TLS + && type2 != elfcpp::PT_TLS + && type2 != elfcpp::PT_GNU_RELRO) + return false; + if (type2 == elfcpp::PT_TLS + && type1 != elfcpp::PT_TLS + && type1 != elfcpp::PT_GNU_RELRO) + return true; + + // We put the PT_GNU_RELRO segment last, because that is where the + // dynamic linker expects to find it (as with PT_TLS, this is just + // for efficiency). + if (type1 == elfcpp::PT_GNU_RELRO && type2 != elfcpp::PT_GNU_RELRO) + return false; + if (type2 == elfcpp::PT_GNU_RELRO && type1 != elfcpp::PT_GNU_RELRO) + return true; + + const elfcpp::Elf_Word flags1 = seg1->flags(); + const elfcpp::Elf_Word flags2 = seg2->flags(); + + // The order of non-PT_LOAD segments is unimportant. We simply sort + // by the numeric segment type and flags values. There should not + // be more than one segment with the same type and flags, except + // when a linker script specifies such. + if (type1 != elfcpp::PT_LOAD) + { + if (type1 != type2) + return type1 < type2; + gold_assert(flags1 != flags2 + || this->script_options_->saw_phdrs_clause()); + return flags1 < flags2; + } + + // If the addresses are set already, sort by load address. + if (seg1->are_addresses_set()) + { + if (!seg2->are_addresses_set()) + return true; + + unsigned int section_count1 = seg1->output_section_count(); + unsigned int section_count2 = seg2->output_section_count(); + if (section_count1 == 0 && section_count2 > 0) + return true; + if (section_count1 > 0 && section_count2 == 0) + return false; + + uint64_t paddr1 = (seg1->are_addresses_set() + ? seg1->paddr() + : seg1->first_section_load_address()); + uint64_t paddr2 = (seg2->are_addresses_set() + ? seg2->paddr() + : seg2->first_section_load_address()); + + if (paddr1 != paddr2) + return paddr1 < paddr2; + } + else if (seg2->are_addresses_set()) + return false; + + // A segment which holds large data comes after a segment which does + // not hold large data. + if (seg1->is_large_data_segment()) + { + if (!seg2->is_large_data_segment()) + return false; + } + else if (seg2->is_large_data_segment()) + return true; + + // Otherwise, we sort PT_LOAD segments based on the flags. Readonly + // segments come before writable segments. Then writable segments + // with data come before writable segments without data. Then + // executable segments come before non-executable segments. Then + // the unlikely case of a non-readable segment comes before the + // normal case of a readable segment. If there are multiple + // segments with the same type and flags, we require that the + // address be set, and we sort by virtual address and then physical + // address. + if ((flags1 & elfcpp::PF_W) != (flags2 & elfcpp::PF_W)) + return (flags1 & elfcpp::PF_W) == 0; + if ((flags1 & elfcpp::PF_W) != 0 + && seg1->has_any_data_sections() != seg2->has_any_data_sections()) + return seg1->has_any_data_sections(); + if ((flags1 & elfcpp::PF_X) != (flags2 & elfcpp::PF_X)) + return (flags1 & elfcpp::PF_X) != 0; + if ((flags1 & elfcpp::PF_R) != (flags2 & elfcpp::PF_R)) + return (flags1 & elfcpp::PF_R) == 0; + + // We shouldn't get here--we shouldn't create segments which we + // can't distinguish. Unless of course we are using a weird linker + // script or overlapping --section-start options. We could also get + // here if plugins want unique segments for subsets of sections. + gold_assert(this->script_options_->saw_phdrs_clause() + || parameters->options().any_section_start() + || this->is_unique_segment_for_sections_specified()); + return false; +} + +// Increase OFF so that it is congruent to ADDR modulo ABI_PAGESIZE. + +static off_t +align_file_offset(off_t off, uint64_t addr, uint64_t abi_pagesize) +{ + uint64_t unsigned_off = off; + uint64_t aligned_off = ((unsigned_off & ~(abi_pagesize - 1)) + | (addr & (abi_pagesize - 1))); + if (aligned_off < unsigned_off) + aligned_off += abi_pagesize; + return aligned_off; +} + +// On targets where the text segment contains only executable code, +// a non-executable segment is never the text segment. + +static inline bool +is_text_segment(const Target* target, const Output_segment* seg) +{ + elfcpp::Elf_Xword flags = seg->flags(); + if ((flags & elfcpp::PF_W) != 0) + return false; + if ((flags & elfcpp::PF_X) == 0) + return !target->isolate_execinstr(); + return true; +} + +// Set the file offsets of all the segments, and all the sections they +// contain. They have all been created. LOAD_SEG must be be laid out +// first. Return the offset of the data to follow. + +off_t +Layout::set_segment_offsets(const Target* target, Output_segment* load_seg, + unsigned int* pshndx) +{ + // Sort them into the final order. We use a stable sort so that we + // don't randomize the order of indistinguishable segments created + // by linker scripts. + std::stable_sort(this->segment_list_.begin(), this->segment_list_.end(), + Layout::Compare_segments(this)); + + // Find the PT_LOAD segments, and set their addresses and offsets + // and their section's addresses and offsets. + uint64_t start_addr; + if (parameters->options().user_set_Ttext()) + start_addr = parameters->options().Ttext(); + else if (parameters->options().output_is_position_independent()) + start_addr = 0; + else + 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 + // will not be loadable. But they still need to be at offset 0 in + // the file. Set their offsets now. + if (load_seg == NULL) + { + for (Data_list::iterator p = this->special_output_list_.begin(); + p != this->special_output_list_.end(); + ++p) + { + off = align_address(off, (*p)->addralign()); + (*p)->set_address_and_file_offset(0, off); + off += (*p)->data_size(); + } + } + + unsigned int increase_relro = this->increase_relro_; + if (this->script_options_->saw_sections_clause()) + increase_relro = 0; + + 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 (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) + { + // When it comes to setting file offsets, we care about + // the physical address. + addr = (*p)->paddr(); + } + else if (parameters->options().user_set_Ttext() + && (parameters->options().omagic() + || is_text_segment(target, *p))) + { + are_addresses_set = true; + } + else if (parameters->options().user_set_Trodata_segment() + && ((*p)->flags() & (elfcpp::PF_W | elfcpp::PF_X)) == 0) + { + addr = parameters->options().Trodata_segment(); + are_addresses_set = true; + } + else if (parameters->options().user_set_Tdata() + && ((*p)->flags() & elfcpp::PF_W) != 0 + && (!parameters->options().user_set_Tbss() + || (*p)->has_any_data_sections())) + { + addr = parameters->options().Tdata(); + are_addresses_set = true; + } + else if (parameters->options().user_set_Tbss() + && ((*p)->flags() & elfcpp::PF_W) != 0 + && !(*p)->has_any_data_sections()) + { + addr = parameters->options().Tbss(); + are_addresses_set = true; + } + + uint64_t orig_addr = addr; + uint64_t orig_off = off; + + uint64_t aligned_addr = 0; + uint64_t abi_pagesize = target->abi_pagesize(); + uint64_t common_pagesize = target->common_pagesize(); + + if (!parameters->options().nmagic() + && !parameters->options().omagic()) + (*p)->set_minimum_p_align(abi_pagesize); + + if (!are_addresses_set) + { + // Skip the address forward one page, maintaining the same + // position within the page. This lets us store both segments + // overlapping on a single page in the file, but the loader will + // put them on different pages in memory. We will revisit this + // decision once we know the size of the segment. + + addr = align_address(addr, (*p)->maximum_alignment()); + aligned_addr = addr; + + 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 + (parameters->options().user_set_rosegment_gap() + ? parameters->options().rosegment_gap() + : 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)); + } + } + + if (!parameters->options().nmagic() + && !parameters->options().omagic()) + { + // Here we are also taking care of the case when + // the maximum segment alignment is larger than the page size. + off = align_file_offset(off, addr, + std::max(abi_pagesize, + (*p)->maximum_alignment())); + } + else + { + // This is -N or -n with a section script which prevents + // us from using a load segment. We need to ensure that + // the file offset is aligned to the alignment of the + // segment. This is because the linker script + // implicitly assumed a zero offset. If we don't align + // here, then the alignment of the sections in the + // linker script may not match the alignment of the + // sections in the set_section_addresses call below, + // causing an error about dot moving backward. + off = align_address(off, (*p)->maximum_alignment()); + } + + unsigned int shndx_hold = *pshndx; + bool has_relro = false; + uint64_t new_addr = (*p)->set_section_addresses(target, this, + false, addr, + &increase_relro, + &has_relro, + &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 + // file space, by instead aligning to the start of a new + // page. Here we use the real machine page size rather than + // the ABI mandated page size. If the segment has been + // aligned so that the relro data ends at a page boundary, + // we do not try to realign it. + + if (!are_addresses_set + && !has_relro + && aligned_addr != addr + && !parameters->incremental()) + { + uint64_t first_off = (common_pagesize + - (aligned_addr + & (common_pagesize - 1))); + uint64_t last_off = new_addr & (common_pagesize - 1); + if (first_off > 0 + && last_off > 0 + && ((aligned_addr & ~ (common_pagesize - 1)) + != (new_addr & ~ (common_pagesize - 1))) + && first_off + last_off <= common_pagesize) + { + *pshndx = shndx_hold; + addr = align_address(aligned_addr, common_pagesize); + addr = align_address(addr, (*p)->maximum_alignment()); + if ((addr & (abi_pagesize - 1)) != 0) + addr = addr + abi_pagesize; + off = orig_off + ((addr - orig_addr) & (abi_pagesize - 1)); + off = align_file_offset(off, addr, abi_pagesize); + + increase_relro = this->increase_relro_; + if (this->script_options_->saw_sections_clause()) + increase_relro = 0; + has_relro = false; + + new_addr = (*p)->set_section_addresses(target, this, + true, addr, + &increase_relro, + &has_relro, + &off, pshndx); + } + } + + addr = new_addr; + + // Implement --check-sections. We know that the segments + // are sorted by LMA. + if (check_sections && last_load_segment != NULL) + { + gold_assert(last_load_segment->paddr() <= (*p)->paddr()); + if (last_load_segment->paddr() + last_load_segment->memsz() + > (*p)->paddr()) + { + unsigned long long lb1 = last_load_segment->paddr(); + unsigned long long le1 = lb1 + last_load_segment->memsz(); + unsigned long long lb2 = (*p)->paddr(); + unsigned long long le2 = lb2 + (*p)->memsz(); + gold_error(_("load segment overlap [0x%llx -> 0x%llx] and " + "[0x%llx -> 0x%llx]"), + lb1, le1, lb2, le2); + } + } + last_load_segment = *p; + } + } + + 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()); + + this->reset_relax_output(); + + 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(target, 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(); + p != this->segment_list_.end(); + ++p) + { + if ((*p)->type() != elfcpp::PT_LOAD) + (*p)->set_offset((*p)->type() == elfcpp::PT_GNU_RELRO + ? increase_relro + : 0); + } + + // Set the TLS offsets for each section in the PT_TLS segment. + if (this->tls_segment_ != NULL) + this->tls_segment_->set_tls_offsets(); + + return off; +} + +// Set the offsets of all the allocated sections when doing a +// relocatable link. This does the same jobs as set_segment_offsets, +// only for a relocatable link. + +off_t +Layout::set_relocatable_section_offsets(Output_data* file_header, + unsigned int* pshndx) +{ + off_t off = 0; + + file_header->set_address_and_file_offset(0, 0); + off += file_header->data_size(); + + for (Section_list::iterator p = this->section_list_.begin(); + p != this->section_list_.end(); + ++p) + { + // We skip unallocated sections here, except that group sections + // have to come first. + if (((*p)->flags() & elfcpp::SHF_ALLOC) == 0 + && (*p)->type() != elfcpp::SHT_GROUP) + continue; + + off = align_address(off, (*p)->addralign()); + + // The linker script might have set the address. + if (!(*p)->is_address_valid()) + (*p)->set_address(0); + (*p)->set_file_offset(off); + (*p)->finalize_data_size(); + if ((*p)->type() != elfcpp::SHT_NOBITS) + off += (*p)->data_size(); + + (*p)->set_out_shndx(*pshndx); + ++*pshndx; + } + + return off; +} + +// Set the file offset of all the sections not associated with a +// segment. + +off_t +Layout::set_section_offsets(off_t off, Layout::Section_offset_pass pass) +{ + off_t startoff = off; + off_t maxoff = off; + + for (Section_list::iterator p = this->unattached_section_list_.begin(); + p != this->unattached_section_list_.end(); + ++p) + { + // The symtab section is handled in create_symtab_sections. + if (*p == this->symtab_section_) + continue; + + // If we've already set the data size, don't set it again. + if ((*p)->is_offset_valid() && (*p)->is_data_size_valid()) + continue; + + if (pass == BEFORE_INPUT_SECTIONS_PASS + && (*p)->requires_postprocessing()) + { + (*p)->create_postprocessing_buffer(); + this->any_postprocessing_sections_ = true; + } + + if (pass == BEFORE_INPUT_SECTIONS_PASS + && (*p)->after_input_sections()) + continue; + else if (pass == POSTPROCESSING_SECTIONS_PASS + && (!(*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; + + if (!parameters->incremental_update()) + { + off = align_address(off, (*p)->addralign()); + (*p)->set_file_offset(off); + (*p)->finalize_data_size(); + } + else + { + // Incremental update: allocate file space from free list. + (*p)->pre_finalize_data_size(); + off_t current_size = (*p)->current_data_size(); + off = this->allocate(current_size, (*p)->addralign(), startoff); + if (off == -1) + { + if (is_debugging_enabled(DEBUG_INCREMENTAL)) + this->free_list_.dump(); + gold_assert((*p)->output_section() != NULL); + gold_fallback(_("out of patch space for section %s; " + "relink with --incremental-full"), + (*p)->output_section()->name()); + } + (*p)->set_file_offset(off); + (*p)->finalize_data_size(); + if ((*p)->data_size() > current_size) + { + gold_assert((*p)->output_section() != NULL); + gold_fallback(_("%s: section changed size; " + "relink with --incremental-full"), + (*p)->output_section()->name()); + } + gold_debug(DEBUG_INCREMENTAL, + "set_section_offsets: %08lx %08lx %s", + static_cast(off), + static_cast((*p)->data_size()), + ((*p)->output_section() != NULL + ? (*p)->output_section()->name() : "(special)")); + } + + off += (*p)->data_size(); + if (off > maxoff) + maxoff = off; + + // At this point the name must be set. + if (pass != STRTAB_AFTER_POSTPROCESSING_SECTIONS_PASS) + this->namepool_.add((*p)->name(), false, NULL); + } + return maxoff; +} + +// Set the section indexes of all the sections not associated with a +// segment. + +unsigned int +Layout::set_section_indexes(unsigned int shndx) +{ + for (Section_list::iterator p = this->unattached_section_list_.begin(); + p != this->unattached_section_list_.end(); + ++p) + { + if (!(*p)->has_out_shndx()) + { + (*p)->set_out_shndx(shndx); + ++shndx; + } + } + return shndx; +} + +// Set the section addresses according to the linker script. This is +// only called when we see a SECTIONS clause. This returns the +// program segment which should hold the file header and segment +// headers, if any. It will return NULL if they should not be in a +// segment. + +Output_segment* +Layout::set_section_addresses_from_script(Symbol_table* symtab) +{ + Script_sections* ss = this->script_options_->script_sections(); + gold_assert(ss->saw_sections_clause()); + return this->script_options_->set_section_addresses(symtab, this); +} + +// Place the orphan sections in the linker script. + +void +Layout::place_orphan_sections_in_script() +{ + Script_sections* ss = this->script_options_->script_sections(); + gold_assert(ss->saw_sections_clause()); + + // Place each orphaned output section in the script. + for (Section_list::iterator p = this->section_list_.begin(); + p != this->section_list_.end(); + ++p) + { + if (!(*p)->found_in_sections_clause()) + ss->place_orphan(*p); + } +} + +// Count the local symbols in the regular symbol table and the dynamic +// symbol table, and build the respective string pools. + +void +Layout::count_local_symbols(const Task* task, + const Input_objects* input_objects) +{ + // First, figure out an upper bound on the number of symbols we'll + // be inserting into each pool. This helps us create the pools with + // the right size, to avoid unnecessary hashtable resizing. + unsigned int symbol_count = 0; + for (Input_objects::Relobj_iterator p = input_objects->relobj_begin(); + p != input_objects->relobj_end(); + ++p) + symbol_count += (*p)->local_symbol_count(); + + // Go from "upper bound" to "estimate." We overcount for two + // reasons: we double-count symbols that occur in more than one + // object file, and we count symbols that are dropped from the + // output. Add it all together and assume we overcount by 100%. + symbol_count /= 2; + + // We assume all symbols will go into both the sympool and dynpool. + this->sympool_.reserve(symbol_count); + this->dynpool_.reserve(symbol_count); + + for (Input_objects::Relobj_iterator p = input_objects->relobj_begin(); + p != input_objects->relobj_end(); + ++p) + { + Task_lock_obj tlo(task, *p); + (*p)->count_local_symbols(&this->sympool_, &this->dynpool_); + } +} + +// Create the symbol table sections. Here we also set the final +// values of the symbols. At this point all the loadable sections are +// fully laid out. SHNUM is the number of sections so far. + +void +Layout::create_symtab_sections(const Input_objects* input_objects, + Symbol_table* symtab, + unsigned int shnum, + off_t* poff) +{ + int symsize; + unsigned int align; + if (parameters->target().get_size() == 32) + { + symsize = elfcpp::Elf_sizes<32>::sym_size; + align = 4; + } + else if (parameters->target().get_size() == 64) + { + symsize = elfcpp::Elf_sizes<64>::sym_size; + align = 8; + } + else + gold_unreachable(); + + // Compute file offsets relative to the start of the symtab section. + off_t off = 0; + + // Save space for the dummy symbol at the start of the section. We + // never bother to write this out--it will just be left as zero. + off += symsize; + unsigned int local_symbol_index = 1; + + // Add STT_SECTION symbols for each Output section which needs one. + for (Section_list::iterator p = this->section_list_.begin(); + p != this->section_list_.end(); + ++p) + { + if (!(*p)->needs_symtab_index()) + (*p)->set_symtab_index(-1U); + else + { + (*p)->set_symtab_index(local_symbol_index); + ++local_symbol_index; + off += symsize; + } + } + + for (Input_objects::Relobj_iterator p = input_objects->relobj_begin(); + p != input_objects->relobj_end(); + ++p) + { + unsigned int index = (*p)->finalize_local_symbols(local_symbol_index, + off, symtab); + off += (index - local_symbol_index) * symsize; + local_symbol_index = index; + } + + unsigned int local_symcount = local_symbol_index; + gold_assert(static_cast(local_symcount * symsize) == off); + + off_t dynoff; + size_t dyn_global_index; + size_t dyncount; + if (this->dynsym_section_ == NULL) + { + dynoff = 0; + dyn_global_index = 0; + dyncount = 0; + } + else + { + dyn_global_index = this->dynsym_section_->info(); + off_t locsize = dyn_global_index * this->dynsym_section_->entsize(); + dynoff = this->dynsym_section_->offset() + locsize; + dyncount = (this->dynsym_section_->data_size() - locsize) / symsize; + gold_assert(static_cast(dyncount * symsize) + == this->dynsym_section_->data_size() - locsize); + } + + off_t global_off = off; + off = symtab->finalize(off, dynoff, dyn_global_index, dyncount, + &this->sympool_, &local_symcount); + + if (!parameters->options().strip_all()) + { + this->sympool_.set_string_offsets(); + + const char* symtab_name = this->namepool_.add(".symtab", false, NULL); + Output_section* osymtab = this->make_output_section(symtab_name, + elfcpp::SHT_SYMTAB, + 0, ORDER_INVALID, + false); + this->symtab_section_ = osymtab; + + Output_section_data* pos = new Output_data_fixed_space(off, align, + "** symtab"); + osymtab->add_output_section_data(pos); + + // We generate a .symtab_shndx section if we have more than + // SHN_LORESERVE sections. Technically it is possible that we + // don't need one, because it is possible that there are no + // symbols in any of sections with indexes larger than + // SHN_LORESERVE. That is probably unusual, though, and it is + // easier to always create one than to compute section indexes + // twice (once here, once when writing out the symbols). + if (shnum >= elfcpp::SHN_LORESERVE) + { + const char* symtab_xindex_name = this->namepool_.add(".symtab_shndx", + false, NULL); + Output_section* osymtab_xindex = + this->make_output_section(symtab_xindex_name, + elfcpp::SHT_SYMTAB_SHNDX, 0, + ORDER_INVALID, false); + + size_t symcount = off / symsize; + this->symtab_xindex_ = new Output_symtab_xindex(symcount); + + osymtab_xindex->add_output_section_data(this->symtab_xindex_); + + osymtab_xindex->set_link_section(osymtab); + osymtab_xindex->set_addralign(4); + osymtab_xindex->set_entsize(4); + + osymtab_xindex->set_after_input_sections(); + + // This tells the driver code to wait until the symbol table + // has written out before writing out the postprocessing + // sections, including the .symtab_shndx section. + this->any_postprocessing_sections_ = true; + } + + const char* strtab_name = this->namepool_.add(".strtab", false, NULL); + Output_section* ostrtab = this->make_output_section(strtab_name, + elfcpp::SHT_STRTAB, + 0, ORDER_INVALID, + false); + + Output_section_data* pstr = new Output_data_strtab(&this->sympool_); + ostrtab->add_output_section_data(pstr); + + off_t symtab_off; + if (!parameters->incremental_update()) + symtab_off = align_address(*poff, align); + else + { + symtab_off = this->allocate(off, align, *poff); + if (off == -1) + gold_fallback(_("out of patch space for symbol table; " + "relink with --incremental-full")); + gold_debug(DEBUG_INCREMENTAL, + "create_symtab_sections: %08lx %08lx .symtab", + static_cast(symtab_off), + static_cast(off)); + } + + symtab->set_file_offset(symtab_off + global_off); + osymtab->set_file_offset(symtab_off); + osymtab->finalize_data_size(); + osymtab->set_link_section(ostrtab); + osymtab->set_info(local_symcount); + osymtab->set_entsize(symsize); + + if (symtab_off + off > *poff) + *poff = symtab_off + off; + } +} + +// Create the .shstrtab section, which holds the names of the +// sections. At the time this is called, we have created all the +// output sections except .shstrtab itself. + +Output_section* +Layout::create_shstrtab() +{ + // FIXME: We don't need to create a .shstrtab section if we are + // stripping everything. + + const char* name = this->namepool_.add(".shstrtab", false, NULL); + + Output_section* os = this->make_output_section(name, elfcpp::SHT_STRTAB, 0, + ORDER_INVALID, false); + + if (strcmp(parameters->options().compress_debug_sections(), "none") != 0) + { + // We can't write out this section until we've set all the + // section names, and we don't set the names of compressed + // output sections until relocations are complete. FIXME: With + // the current names we use, this is unnecessary. + os->set_after_input_sections(); + } + + Output_section_data* posd = new Output_data_strtab(&this->namepool_); + os->add_output_section_data(posd); + + return os; +} + +// Create the section headers. SIZE is 32 or 64. OFF is the file +// offset. + +void +Layout::create_shdrs(const Output_section* shstrtab_section, off_t* poff) +{ + Output_section_headers* oshdrs; + oshdrs = new Output_section_headers(this, + &this->segment_list_, + &this->section_list_, + &this->unattached_section_list_, + &this->namepool_, + shstrtab_section); + off_t off; + if (!parameters->incremental_update()) + off = align_address(*poff, oshdrs->addralign()); + else + { + oshdrs->pre_finalize_data_size(); + off = this->allocate(oshdrs->data_size(), oshdrs->addralign(), *poff); + if (off == -1) + gold_fallback(_("out of patch space for section header table; " + "relink with --incremental-full")); + gold_debug(DEBUG_INCREMENTAL, + "create_shdrs: %08lx %08lx (section header table)", + static_cast(off), + static_cast(off + oshdrs->data_size())); + } + oshdrs->set_address_and_file_offset(0, off); + off += oshdrs->data_size(); + if (off > *poff) + *poff = off; + this->section_headers_ = oshdrs; +} + +// Count the allocated sections. + +size_t +Layout::allocated_output_section_count() const +{ + size_t section_count = 0; + for (Segment_list::const_iterator p = this->segment_list_.begin(); + p != this->segment_list_.end(); + ++p) + section_count += (*p)->output_section_count(); + return section_count; +} + +// Create the dynamic symbol table. + +void +Layout::create_dynamic_symtab(const Input_objects* input_objects, + Symbol_table* symtab, + Output_section** pdynstr, + unsigned int* plocal_dynamic_count, + std::vector* pdynamic_symbols, + Versions* pversions) +{ + // Count all the symbols in the dynamic symbol table, and set the + // dynamic symbol indexes. + + // Skip symbol 0, which is always all zeroes. + unsigned int index = 1; + + // Add STT_SECTION symbols for each Output section which needs one. + for (Section_list::iterator p = this->section_list_.begin(); + p != this->section_list_.end(); + ++p) + { + if (!(*p)->needs_dynsym_index()) + (*p)->set_dynsym_index(-1U); + else + { + (*p)->set_dynsym_index(index); + ++index; + } + } + + // Count the local symbols that need to go in the dynamic symbol table, + // and set the dynamic symbol indexes. + for (Input_objects::Relobj_iterator p = input_objects->relobj_begin(); + p != input_objects->relobj_end(); + ++p) + { + unsigned int new_index = (*p)->set_local_dynsym_indexes(index); + index = new_index; + } + + unsigned int local_symcount = index; + *plocal_dynamic_count = local_symcount; + + index = symtab->set_dynsym_indexes(index, pdynamic_symbols, + &this->dynpool_, pversions); + + int symsize; + unsigned int align; + const int size = parameters->target().get_size(); + if (size == 32) + { + symsize = elfcpp::Elf_sizes<32>::sym_size; + align = 4; + } + else if (size == 64) + { + symsize = elfcpp::Elf_sizes<64>::sym_size; + align = 8; + } + else + gold_unreachable(); + + // Create the dynamic symbol table section. + + Output_section* dynsym = this->choose_output_section(NULL, ".dynsym", + elfcpp::SHT_DYNSYM, + elfcpp::SHF_ALLOC, + false, + ORDER_DYNAMIC_LINKER, + false); + + // Check for NULL as a linker script may discard .dynsym. + if (dynsym != NULL) + { + Output_section_data* odata = new Output_data_fixed_space(index * symsize, + align, + "** dynsym"); + dynsym->add_output_section_data(odata); + + dynsym->set_info(local_symcount); + dynsym->set_entsize(symsize); + dynsym->set_addralign(align); + + this->dynsym_section_ = dynsym; + } + + Output_data_dynamic* const odyn = this->dynamic_data_; + if (odyn != NULL) + { + odyn->add_section_address(elfcpp::DT_SYMTAB, dynsym); + odyn->add_constant(elfcpp::DT_SYMENT, symsize); + } + + // If there are more than SHN_LORESERVE allocated sections, we + // create a .dynsym_shndx section. It is possible that we don't + // need one, because it is possible that there are no dynamic + // symbols in any of the sections with indexes larger than + // SHN_LORESERVE. This is probably unusual, though, and at this + // time we don't know the actual section indexes so it is + // inconvenient to check. + if (this->allocated_output_section_count() >= elfcpp::SHN_LORESERVE) + { + Output_section* dynsym_xindex = + this->choose_output_section(NULL, ".dynsym_shndx", + elfcpp::SHT_SYMTAB_SHNDX, + elfcpp::SHF_ALLOC, + false, ORDER_DYNAMIC_LINKER, false); + + if (dynsym_xindex != NULL) + { + this->dynsym_xindex_ = new Output_symtab_xindex(index); + + dynsym_xindex->add_output_section_data(this->dynsym_xindex_); + + dynsym_xindex->set_link_section(dynsym); + dynsym_xindex->set_addralign(4); + dynsym_xindex->set_entsize(4); + + dynsym_xindex->set_after_input_sections(); + + // This tells the driver code to wait until the symbol table + // has written out before writing out the postprocessing + // sections, including the .dynsym_shndx section. + this->any_postprocessing_sections_ = true; + } + } + + // Create the dynamic string table section. + + Output_section* dynstr = this->choose_output_section(NULL, ".dynstr", + elfcpp::SHT_STRTAB, + elfcpp::SHF_ALLOC, + false, + ORDER_DYNAMIC_LINKER, + false); + *pdynstr = dynstr; + if (dynstr != NULL) + { + Output_section_data* strdata = new Output_data_strtab(&this->dynpool_); + dynstr->add_output_section_data(strdata); + + if (dynsym != NULL) + dynsym->set_link_section(dynstr); + if (this->dynamic_section_ != NULL) + this->dynamic_section_->set_link_section(dynstr); + + if (odyn != NULL) + { + odyn->add_section_address(elfcpp::DT_STRTAB, dynstr); + odyn->add_section_size(elfcpp::DT_STRSZ, dynstr); + } + } + + // Create the hash tables. + + if (strcmp(parameters->options().hash_style(), "sysv") == 0 + || strcmp(parameters->options().hash_style(), "both") == 0) + { + unsigned char* phash; + unsigned int hashlen; + Dynobj::create_elf_hash_table(*pdynamic_symbols, local_symcount, + &phash, &hashlen); + + Output_section* hashsec = + this->choose_output_section(NULL, ".hash", elfcpp::SHT_HASH, + elfcpp::SHF_ALLOC, false, + ORDER_DYNAMIC_LINKER, false); + + Output_section_data* hashdata = new Output_data_const_buffer(phash, + hashlen, + align, + "** hash"); + if (hashsec != NULL && hashdata != NULL) + hashsec->add_output_section_data(hashdata); + + if (hashsec != NULL) + { + if (dynsym != NULL) + hashsec->set_link_section(dynsym); + hashsec->set_entsize(4); + } + + if (odyn != NULL) + odyn->add_section_address(elfcpp::DT_HASH, hashsec); + } + + if (strcmp(parameters->options().hash_style(), "gnu") == 0 + || strcmp(parameters->options().hash_style(), "both") == 0) + { + unsigned char* phash; + unsigned int hashlen; + Dynobj::create_gnu_hash_table(*pdynamic_symbols, local_symcount, + &phash, &hashlen); + + Output_section* hashsec = + this->choose_output_section(NULL, ".gnu.hash", elfcpp::SHT_GNU_HASH, + elfcpp::SHF_ALLOC, false, + ORDER_DYNAMIC_LINKER, false); + + Output_section_data* hashdata = new Output_data_const_buffer(phash, + hashlen, + align, + "** hash"); + if (hashsec != NULL && hashdata != NULL) + hashsec->add_output_section_data(hashdata); + + if (hashsec != NULL) + { + if (dynsym != NULL) + hashsec->set_link_section(dynsym); + + // For a 64-bit target, the entries in .gnu.hash do not have + // a uniform size, so we only set the entry size for a + // 32-bit target. + if (parameters->target().get_size() == 32) + hashsec->set_entsize(4); + + if (odyn != NULL) + odyn->add_section_address(elfcpp::DT_GNU_HASH, hashsec); + } + } +} + +// Assign offsets to each local portion of the dynamic symbol table. + +void +Layout::assign_local_dynsym_offsets(const Input_objects* input_objects) +{ + Output_section* dynsym = this->dynsym_section_; + if (dynsym == NULL) + return; + + off_t off = dynsym->offset(); + + // Skip the dummy symbol at the start of the section. + off += dynsym->entsize(); + + for (Input_objects::Relobj_iterator p = input_objects->relobj_begin(); + p != input_objects->relobj_end(); + ++p) + { + unsigned int count = (*p)->set_local_dynsym_offset(off); + off += count * dynsym->entsize(); + } +} + +// Create the version sections. + +void +Layout::create_version_sections(const Versions* versions, + const Symbol_table* symtab, + unsigned int local_symcount, + const std::vector& dynamic_symbols, + const Output_section* dynstr) +{ + if (!versions->any_defs() && !versions->any_needs()) + return; + + switch (parameters->size_and_endianness()) + { +#ifdef HAVE_TARGET_32_LITTLE + case Parameters::TARGET_32_LITTLE: + this->sized_create_version_sections<32, false>(versions, symtab, + local_symcount, + dynamic_symbols, dynstr); + break; +#endif +#ifdef HAVE_TARGET_32_BIG + case Parameters::TARGET_32_BIG: + this->sized_create_version_sections<32, true>(versions, symtab, + local_symcount, + dynamic_symbols, dynstr); + break; +#endif +#ifdef HAVE_TARGET_64_LITTLE + case Parameters::TARGET_64_LITTLE: + this->sized_create_version_sections<64, false>(versions, symtab, + local_symcount, + dynamic_symbols, dynstr); + break; +#endif +#ifdef HAVE_TARGET_64_BIG + case Parameters::TARGET_64_BIG: + this->sized_create_version_sections<64, true>(versions, symtab, + local_symcount, + dynamic_symbols, dynstr); + break; +#endif + default: + gold_unreachable(); + } +} + +// Create the version sections, sized version. + +template +void +Layout::sized_create_version_sections( + const Versions* versions, + const Symbol_table* symtab, + unsigned int local_symcount, + const std::vector& dynamic_symbols, + const Output_section* dynstr) +{ + Output_section* vsec = this->choose_output_section(NULL, ".gnu.version", + elfcpp::SHT_GNU_versym, + elfcpp::SHF_ALLOC, + false, + ORDER_DYNAMIC_LINKER, + false); + + // Check for NULL since a linker script may discard this section. + if (vsec != NULL) + { + unsigned char* vbuf; + unsigned int vsize; + versions->symbol_section_contents(symtab, + &this->dynpool_, + local_symcount, + dynamic_symbols, + &vbuf, &vsize); + + Output_section_data* vdata = new Output_data_const_buffer(vbuf, vsize, 2, + "** versions"); + + vsec->add_output_section_data(vdata); + vsec->set_entsize(2); + vsec->set_link_section(this->dynsym_section_); + } + + Output_data_dynamic* const odyn = this->dynamic_data_; + if (odyn != NULL && vsec != NULL) + odyn->add_section_address(elfcpp::DT_VERSYM, vsec); + + if (versions->any_defs()) + { + Output_section* vdsec; + vdsec = this->choose_output_section(NULL, ".gnu.version_d", + elfcpp::SHT_GNU_verdef, + elfcpp::SHF_ALLOC, + false, ORDER_DYNAMIC_LINKER, false); + + if (vdsec != NULL) + { + unsigned char* vdbuf; + unsigned int vdsize; + unsigned int vdentries; + versions->def_section_contents(&this->dynpool_, + &vdbuf, &vdsize, + &vdentries); + + Output_section_data* vddata = + new Output_data_const_buffer(vdbuf, vdsize, 4, "** version defs"); + + vdsec->add_output_section_data(vddata); + vdsec->set_link_section(dynstr); + vdsec->set_info(vdentries); + + if (odyn != NULL) + { + odyn->add_section_address(elfcpp::DT_VERDEF, vdsec); + odyn->add_constant(elfcpp::DT_VERDEFNUM, vdentries); + } + } + } + + if (versions->any_needs()) + { + Output_section* vnsec; + vnsec = this->choose_output_section(NULL, ".gnu.version_r", + elfcpp::SHT_GNU_verneed, + elfcpp::SHF_ALLOC, + false, ORDER_DYNAMIC_LINKER, false); + + if (vnsec != NULL) + { + unsigned char* vnbuf; + unsigned int vnsize; + unsigned int vnentries; + versions->need_section_contents(&this->dynpool_, + &vnbuf, &vnsize, + &vnentries); + + Output_section_data* vndata = + new Output_data_const_buffer(vnbuf, vnsize, 4, "** version refs"); + + vnsec->add_output_section_data(vndata); + vnsec->set_link_section(dynstr); + vnsec->set_info(vnentries); + + if (odyn != NULL) + { + odyn->add_section_address(elfcpp::DT_VERNEED, vnsec); + odyn->add_constant(elfcpp::DT_VERNEEDNUM, vnentries); + } + } + } +} + +// Create the .interp section and PT_INTERP segment. + +void +Layout::create_interp(const Target* target) +{ + gold_assert(this->interp_segment_ == NULL); + + const char* interp = parameters->options().dynamic_linker(); + if (interp == NULL) + { + interp = target->dynamic_linker(); + gold_assert(interp != NULL); + } + + size_t len = strlen(interp) + 1; + + Output_section_data* odata = new Output_data_const(interp, len, 1); + + Output_section* osec = this->choose_output_section(NULL, ".interp", + elfcpp::SHT_PROGBITS, + elfcpp::SHF_ALLOC, + false, ORDER_INTERP, + false); + if (osec != NULL) + osec->add_output_section_data(odata); +} + +// Add dynamic tags for the PLT and the dynamic relocs. This is +// called by the target-specific code. This does nothing if not doing +// a dynamic link. + +// USE_REL is true for REL relocs rather than RELA relocs. + +// If PLT_GOT is not NULL, then DT_PLTGOT points to it. + +// If PLT_REL is not NULL, it is used for DT_PLTRELSZ, and DT_JMPREL, +// and we also set DT_PLTREL. We use PLT_REL's output section, since +// some targets have multiple reloc sections in PLT_REL. + +// If DYN_REL is not NULL, it is used for DT_REL/DT_RELA, +// DT_RELSZ/DT_RELASZ, DT_RELENT/DT_RELAENT. Again we use the output +// section. + +// If ADD_DEBUG is true, we add a DT_DEBUG entry when generating an +// executable. + +void +Layout::add_target_dynamic_tags(bool use_rel, const Output_data* plt_got, + const Output_data* plt_rel, + const Output_data_reloc_generic* dyn_rel, + bool add_debug, bool dynrel_includes_plt) +{ + Output_data_dynamic* odyn = this->dynamic_data_; + if (odyn == NULL) + return; + + if (plt_got != NULL && plt_got->output_section() != NULL) + odyn->add_section_address(elfcpp::DT_PLTGOT, plt_got); + + if (plt_rel != NULL && plt_rel->output_section() != NULL) + { + odyn->add_section_size(elfcpp::DT_PLTRELSZ, plt_rel->output_section()); + odyn->add_section_address(elfcpp::DT_JMPREL, plt_rel->output_section()); + odyn->add_constant(elfcpp::DT_PLTREL, + use_rel ? elfcpp::DT_REL : elfcpp::DT_RELA); + } + + if ((dyn_rel != NULL && dyn_rel->output_section() != NULL) + || (dynrel_includes_plt + && plt_rel != NULL + && plt_rel->output_section() != NULL)) + { + bool have_dyn_rel = dyn_rel != NULL && dyn_rel->output_section() != NULL; + bool have_plt_rel = plt_rel != NULL && plt_rel->output_section() != NULL; + odyn->add_section_address(use_rel ? elfcpp::DT_REL : elfcpp::DT_RELA, + (have_dyn_rel + ? dyn_rel->output_section() + : plt_rel->output_section())); + elfcpp::DT size_tag = use_rel ? elfcpp::DT_RELSZ : elfcpp::DT_RELASZ; + if (have_dyn_rel && have_plt_rel && dynrel_includes_plt) + odyn->add_section_size(size_tag, + dyn_rel->output_section(), + plt_rel->output_section()); + else if (have_dyn_rel) + odyn->add_section_size(size_tag, dyn_rel->output_section()); + else + odyn->add_section_size(size_tag, plt_rel->output_section()); + const int size = parameters->target().get_size(); + elfcpp::DT rel_tag; + int rel_size; + if (use_rel) + { + rel_tag = elfcpp::DT_RELENT; + if (size == 32) + rel_size = Reloc_types::reloc_size; + else if (size == 64) + rel_size = Reloc_types::reloc_size; + else + gold_unreachable(); + } + else + { + rel_tag = elfcpp::DT_RELAENT; + if (size == 32) + rel_size = Reloc_types::reloc_size; + else if (size == 64) + rel_size = Reloc_types::reloc_size; + else + gold_unreachable(); + } + odyn->add_constant(rel_tag, rel_size); + + if (parameters->options().combreloc() && have_dyn_rel) + { + size_t c = dyn_rel->relative_reloc_count(); + if (c > 0) + odyn->add_constant((use_rel + ? elfcpp::DT_RELCOUNT + : elfcpp::DT_RELACOUNT), + c); + } + } + + if (add_debug && !parameters->options().shared()) + { + // The value of the DT_DEBUG tag is filled in by the dynamic + // linker at run time, and used by the debugger. + odyn->add_constant(elfcpp::DT_DEBUG, 0); + } +} + +// Finish the .dynamic section and PT_DYNAMIC segment. + +void +Layout::finish_dynamic_section(const Input_objects* input_objects, + const Symbol_table* symtab) +{ + if (!this->script_options_->saw_phdrs_clause() + && this->dynamic_section_ != NULL) + { + Output_segment* oseg = this->make_output_segment(elfcpp::PT_DYNAMIC, + (elfcpp::PF_R + | elfcpp::PF_W)); + oseg->add_output_section_to_nonload(this->dynamic_section_, + elfcpp::PF_R | elfcpp::PF_W); + } + + Output_data_dynamic* const odyn = this->dynamic_data_; + if (odyn == NULL) + return; + + for (Input_objects::Dynobj_iterator p = input_objects->dynobj_begin(); + p != input_objects->dynobj_end(); + ++p) + { + if (!(*p)->is_needed() && (*p)->as_needed()) + { + // This dynamic object was linked with --as-needed, but it + // is not needed. + continue; + } + + odyn->add_string(elfcpp::DT_NEEDED, (*p)->soname()); + } + + if (parameters->options().shared()) + { + const char* soname = parameters->options().soname(); + if (soname != NULL) + odyn->add_string(elfcpp::DT_SONAME, soname); + } + + Symbol* sym = symtab->lookup(parameters->options().init()); + if (sym != NULL && sym->is_defined() && !sym->is_from_dynobj()) + odyn->add_symbol(elfcpp::DT_INIT, sym); + + sym = symtab->lookup(parameters->options().fini()); + if (sym != NULL && sym->is_defined() && !sym->is_from_dynobj()) + odyn->add_symbol(elfcpp::DT_FINI, sym); + + // Look for .init_array, .preinit_array and .fini_array by checking + // section types. + for(Layout::Section_list::const_iterator p = this->section_list_.begin(); + p != this->section_list_.end(); + ++p) + switch((*p)->type()) + { + case elfcpp::SHT_FINI_ARRAY: + odyn->add_section_address(elfcpp::DT_FINI_ARRAY, *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); + break; + case elfcpp::SHT_PREINIT_ARRAY: + odyn->add_section_address(elfcpp::DT_PREINIT_ARRAY, *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) + if (q->name() == p->name()) + break; + if (q == p) + { + rpath_val += ':'; + rpath_val += p->name(); + } + } + } + + if (!parameters->options().enable_new_dtags()) + odyn->add_string(elfcpp::DT_RPATH, rpath_val); + else + odyn->add_string(elfcpp::DT_RUNPATH, rpath_val); + } + + // Look for text segments that have dynamic relocations. + bool have_textrel = false; + 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)->flags() & elfcpp::PF_W) == 0 + && (*p)->has_dynamic_reloc()) + { + have_textrel = true; + break; + } + } + } + else + { + // We don't know the section -> segment mapping, so we are + // conservative and just look for readonly sections with + // 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; + } + } + } + + if (parameters->options().filter() != NULL) + odyn->add_string(elfcpp::DT_FILTER, parameters->options().filter()); + if (parameters->options().any_auxiliary()) + { + for (options::String_set::const_iterator p = + parameters->options().auxiliary_begin(); + p != parameters->options().auxiliary_end(); + ++p) + odyn->add_string(elfcpp::DT_AUXILIARY, *p); + } + + // Add a DT_FLAGS entry if necessary. + unsigned int flags = 0; + if (have_textrel) + { + // Add a DT_TEXTREL for compatibility with older loaders. + odyn->add_constant(elfcpp::DT_TEXTREL, 0); + flags |= elfcpp::DF_TEXTREL; + + if (parameters->options().text()) + gold_error(_("read-only segment has dynamic relocations")); + else if (parameters->options().warn_shared_textrel() + && parameters->options().shared()) + gold_warning(_("shared library text segment is not shareable")); + } + if (parameters->options().shared() && this->has_static_tls()) + flags |= elfcpp::DF_STATIC_TLS; + if (parameters->options().origin()) + flags |= elfcpp::DF_ORIGIN; + if (parameters->options().Bsymbolic()) + { + flags |= elfcpp::DF_SYMBOLIC; + // Add DT_SYMBOLIC for compatibility with older loaders. + odyn->add_constant(elfcpp::DT_SYMBOLIC, 0); + } + if (parameters->options().now()) + flags |= elfcpp::DF_BIND_NOW; + if (flags != 0) + odyn->add_constant(elfcpp::DT_FLAGS, flags); + + flags = 0; + if (parameters->options().initfirst()) + flags |= elfcpp::DF_1_INITFIRST; + if (parameters->options().interpose()) + flags |= elfcpp::DF_1_INTERPOSE; + if (parameters->options().loadfltr()) + flags |= elfcpp::DF_1_LOADFLTR; + if (parameters->options().nodefaultlib()) + flags |= elfcpp::DF_1_NODEFLIB; + if (parameters->options().nodelete()) + flags |= elfcpp::DF_1_NODELETE; + if (parameters->options().nodlopen()) + flags |= elfcpp::DF_1_NOOPEN; + if (parameters->options().nodump()) + flags |= elfcpp::DF_1_NODUMP; + if (!parameters->options().shared()) + flags &= ~(elfcpp::DF_1_INITFIRST + | elfcpp::DF_1_NODELETE + | elfcpp::DF_1_NOOPEN); + if (parameters->options().origin()) + flags |= elfcpp::DF_1_ORIGIN; + if (parameters->options().now()) + flags |= elfcpp::DF_1_NOW; + if (parameters->options().Bgroup()) + flags |= elfcpp::DF_1_GROUP; + if (flags != 0) + odyn->add_constant(elfcpp::DT_FLAGS_1, flags); +} + +// Set the size of the _DYNAMIC symbol table to be the size of the +// dynamic data. + +void +Layout::set_dynamic_symbol_size(const Symbol_table* symtab) +{ + Output_data_dynamic* const odyn = this->dynamic_data_; + if (odyn == NULL) + return; + odyn->finalize_data_size(); + if (this->dynamic_symbol_ == NULL) + return; + off_t data_size = odyn->data_size(); + const int size = parameters->target().get_size(); + if (size == 32) + symtab->get_sized_symbol<32>(this->dynamic_symbol_)->set_symsize(data_size); + else if (size == 64) + symtab->get_sized_symbol<64>(this->dynamic_symbol_)->set_symsize(data_size); + else + gold_unreachable(); +} + +// The mapping of input section name prefixes to output section names. +// In some cases one prefix is itself a prefix of another prefix; in +// such a case the longer prefix must come first. These prefixes are +// based on the GNU linker default ELF linker script. + +#define MAPPING_INIT(f, t) { f, sizeof(f) - 1, t, sizeof(t) - 1 } +#define MAPPING_INIT_EXACT(f, t) { f, 0, t, sizeof(t) - 1 } +const Layout::Section_name_mapping Layout::section_name_mapping[] = +{ + MAPPING_INIT(".text.", ".text"), + MAPPING_INIT(".rodata.", ".rodata"), + MAPPING_INIT(".data.rel.ro.local.", ".data.rel.ro.local"), + MAPPING_INIT_EXACT(".data.rel.ro.local", ".data.rel.ro.local"), + MAPPING_INIT(".data.rel.ro.", ".data.rel.ro"), + MAPPING_INIT_EXACT(".data.rel.ro", ".data.rel.ro"), + MAPPING_INIT(".data.", ".data"), + MAPPING_INIT(".bss.", ".bss"), + MAPPING_INIT(".tdata.", ".tdata"), + MAPPING_INIT(".tbss.", ".tbss"), + MAPPING_INIT(".init_array.", ".init_array"), + MAPPING_INIT(".fini_array.", ".fini_array"), + MAPPING_INIT(".sdata.", ".sdata"), + MAPPING_INIT(".sbss.", ".sbss"), + // FIXME: In the GNU linker, .sbss2 and .sdata2 are handled + // differently depending on whether it is creating a shared library. + MAPPING_INIT(".sdata2.", ".sdata"), + MAPPING_INIT(".sbss2.", ".sbss"), + MAPPING_INIT(".lrodata.", ".lrodata"), + MAPPING_INIT(".ldata.", ".ldata"), + MAPPING_INIT(".lbss.", ".lbss"), + MAPPING_INIT(".gcc_except_table.", ".gcc_except_table"), + MAPPING_INIT(".gnu.linkonce.d.rel.ro.local.", ".data.rel.ro.local"), + MAPPING_INIT(".gnu.linkonce.d.rel.ro.", ".data.rel.ro"), + MAPPING_INIT(".gnu.linkonce.t.", ".text"), + MAPPING_INIT(".gnu.linkonce.r.", ".rodata"), + MAPPING_INIT(".gnu.linkonce.d.", ".data"), + MAPPING_INIT(".gnu.linkonce.b.", ".bss"), + MAPPING_INIT(".gnu.linkonce.s.", ".sdata"), + MAPPING_INIT(".gnu.linkonce.sb.", ".sbss"), + MAPPING_INIT(".gnu.linkonce.s2.", ".sdata"), + MAPPING_INIT(".gnu.linkonce.sb2.", ".sbss"), + MAPPING_INIT(".gnu.linkonce.wi.", ".debug_info"), + MAPPING_INIT(".gnu.linkonce.td.", ".tdata"), + MAPPING_INIT(".gnu.linkonce.tb.", ".tbss"), + MAPPING_INIT(".gnu.linkonce.lr.", ".lrodata"), + MAPPING_INIT(".gnu.linkonce.l.", ".ldata"), + MAPPING_INIT(".gnu.linkonce.lb.", ".lbss"), + MAPPING_INIT(".ARM.extab", ".ARM.extab"), + MAPPING_INIT(".gnu.linkonce.armextab.", ".ARM.extab"), + MAPPING_INIT(".ARM.exidx", ".ARM.exidx"), + MAPPING_INIT(".gnu.linkonce.armexidx.", ".ARM.exidx"), +}; +#undef MAPPING_INIT +#undef MAPPING_INIT_EXACT + +const int Layout::section_name_mapping_count = + (sizeof(Layout::section_name_mapping) + / sizeof(Layout::section_name_mapping[0])); + +// Choose the output section name to use given an input section name. +// Set *PLEN to the length of the name. *PLEN is initialized to the +// length of NAME. + +const char* +Layout::output_section_name(const Relobj* relobj, const char* name, + size_t* plen) +{ + // gcc 4.3 generates the following sorts of section names when it + // needs a section name specific to a function: + // .text.FN + // .rodata.FN + // .sdata2.FN + // .data.FN + // .data.rel.FN + // .data.rel.local.FN + // .data.rel.ro.FN + // .data.rel.ro.local.FN + // .sdata.FN + // .bss.FN + // .sbss.FN + // .tdata.FN + // .tbss.FN + + // The GNU linker maps all of those to the part before the .FN, + // except that .data.rel.local.FN is mapped to .data, and + // .data.rel.ro.local.FN is mapped to .data.rel.ro. The sections + // beginning with .data.rel.ro.local are grouped together. + + // For an anonymous namespace, the string FN can contain a '.'. + + // Also of interest: .rodata.strN.N, .rodata.cstN, both of which the + // GNU linker maps to .rodata. + + // The .data.rel.ro sections are used with -z relro. The sections + // are recognized by name. We use the same names that the GNU + // linker does for these sections. + + // It is hard to handle this in a principled way, so we don't even + // try. We use a table of mappings. If the input section name is + // not found in the table, we simply use it as the output section + // name. + + const Section_name_mapping* psnm = section_name_mapping; + for (int i = 0; i < section_name_mapping_count; ++i, ++psnm) + { + if (psnm->fromlen > 0) + { + if (strncmp(name, psnm->from, psnm->fromlen) == 0) + { + *plen = psnm->tolen; + return psnm->to; + } + } + else + { + if (strcmp(name, psnm->from) == 0) + { + *plen = psnm->tolen; + return psnm->to; + } + } + } + + // As an additional complication, .ctors sections are output in + // either .ctors or .init_array sections, and .dtors sections are + // output in either .dtors or .fini_array sections. + if (is_prefix_of(".ctors.", name) || is_prefix_of(".dtors.", name)) + { + if (parameters->options().ctors_in_init_array()) + { + *plen = 11; + return name[1] == 'c' ? ".init_array" : ".fini_array"; + } + else + { + *plen = 6; + return name[1] == 'c' ? ".ctors" : ".dtors"; + } + } + if (parameters->options().ctors_in_init_array() + && (strcmp(name, ".ctors") == 0 || strcmp(name, ".dtors") == 0)) + { + // To make .init_array/.fini_array work with gcc we must exclude + // .ctors and .dtors sections from the crtbegin and crtend + // files. + if (relobj == NULL + || (!Layout::match_file_name(relobj, "crtbegin") + && !Layout::match_file_name(relobj, "crtend"))) + { + *plen = 11; + return name[1] == 'c' ? ".init_array" : ".fini_array"; + } + } + + return name; +} + +// Return true if RELOBJ is an input file whose base name matches +// FILE_NAME. The base name must have an extension of ".o", and must +// be exactly FILE_NAME.o or FILE_NAME, one character, ".o". This is +// to match crtbegin.o as well as crtbeginS.o without getting confused +// by other possibilities. Overall matching the file name this way is +// a dreadful hack, but the GNU linker does it in order to better +// support gcc, and we need to be compatible. + +bool +Layout::match_file_name(const Relobj* relobj, const char* match) +{ + const std::string& file_name(relobj->name()); + const char* base_name = lbasename(file_name.c_str()); + size_t match_len = strlen(match); + if (strncmp(base_name, match, match_len) != 0) + return false; + size_t base_len = strlen(base_name); + if (base_len != match_len + 2 && base_len != match_len + 3) + return false; + return memcmp(base_name + base_len - 2, ".o", 2) == 0; +} + +// Check if a comdat group or .gnu.linkonce section with the given +// NAME is selected for the link. If there is already a section, +// *KEPT_SECTION is set to point to the existing section and the +// function returns false. Otherwise, OBJECT, SHNDX, IS_COMDAT, and +// IS_GROUP_NAME are recorded for this NAME in the layout object, +// *KEPT_SECTION is set to the internal copy and the function returns +// true. + +bool +Layout::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) +{ + // 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++ + // program, and we resize to get more space to minimize rehashing. + if (this->signatures_.size() > 4 + && !this->resized_signatures_) + { + reserve_unordered_map(&this->signatures_, + this->number_of_input_files_ * 64); + this->resized_signatures_ = true; + } + + Kept_section candidate; + std::pair ins = + this->signatures_.insert(std::make_pair(name, candidate)); + + if (kept_section != NULL) + *kept_section = &ins.first->second; + if (ins.second) + { + // This is the first time we've seen this signature. + ins.first->second.set_object(object); + ins.first->second.set_shndx(shndx); + if (is_comdat) + ins.first->second.set_is_comdat(); + if (is_group_name) + ins.first->second.set_is_group_name(); + return true; + } + + // We have already seen this signature. + + if (ins.first->second.is_group_name()) + { + // We've already seen a real section group with this signature. + // 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()) + { + ins.first->second.set_object(object); + ins.first->second.set_shndx(shndx); + return true; + } + return false; + } + else if (is_group_name) + { + // This is a real section group, and we've already seen a + // linkonce section with this signature. Record that we've seen + // a section group, and don't include this section group. + ins.first->second.set_is_group_name(); + return false; + } + else + { + // We've already seen a linkonce section and this is a linkonce + // section. These don't block each other--this may be the same + // symbol name with different section types. + return true; + } +} + +// Store the allocated sections into the section list. + +void +Layout::get_allocated_sections(Section_list* section_list) const +{ + for (Section_list::const_iterator p = this->section_list_.begin(); + p != this->section_list_.end(); + ++p) + if (((*p)->flags() & elfcpp::SHF_ALLOC) != 0) + section_list->push_back(*p); +} + +// Store the executable sections into the section list. + +void +Layout::get_executable_sections(Section_list* section_list) const +{ + for (Section_list::const_iterator p = this->section_list_.begin(); + p != this->section_list_.end(); + ++p) + if (((*p)->flags() & (elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR)) + == (elfcpp::SHF_ALLOC | elfcpp::SHF_EXECINSTR)) + section_list->push_back(*p); +} + +// Create an output segment. + +Output_segment* +Layout::make_output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags) +{ + gold_assert(!parameters->options().relocatable()); + Output_segment* oseg = new Output_segment(type, flags); + this->segment_list_.push_back(oseg); + + if (type == elfcpp::PT_TLS) + this->tls_segment_ = oseg; + else if (type == elfcpp::PT_GNU_RELRO) + this->relro_segment_ = oseg; + else if (type == elfcpp::PT_INTERP) + this->interp_segment_ = oseg; + + return oseg; +} + +// Return the file offset of the normal symbol table. + +off_t +Layout::symtab_section_offset() const +{ + if (this->symtab_section_ != NULL) + return this->symtab_section_->offset(); + return 0; +} + +// Return the section index of the normal symbol table. It may have +// been stripped by the -s/--strip-all option. + +unsigned int +Layout::symtab_section_shndx() const +{ + if (this->symtab_section_ != NULL) + return this->symtab_section_->out_shndx(); + return 0; +} + +// Write out the Output_sections. Most won't have anything to write, +// since most of the data will come from input sections which are +// handled elsewhere. But some Output_sections do have Output_data. + +void +Layout::write_output_sections(Output_file* of) const +{ + for (Section_list::const_iterator p = this->section_list_.begin(); + p != this->section_list_.end(); + ++p) + { + if (!(*p)->after_input_sections()) + (*p)->write(of); + } +} + +// Write out data not associated with a section or the symbol table. + +void +Layout::write_data(const Symbol_table* symtab, Output_file* of) const +{ + if (!parameters->options().strip_all()) + { + const Output_section* symtab_section = this->symtab_section_; + for (Section_list::const_iterator p = this->section_list_.begin(); + p != this->section_list_.end(); + ++p) + { + if ((*p)->needs_symtab_index()) + { + gold_assert(symtab_section != NULL); + unsigned int index = (*p)->symtab_index(); + gold_assert(index > 0 && index != -1U); + off_t off = (symtab_section->offset() + + index * symtab_section->entsize()); + symtab->write_section_symbol(*p, this->symtab_xindex_, of, off); + } + } + } + + const Output_section* dynsym_section = this->dynsym_section_; + for (Section_list::const_iterator p = this->section_list_.begin(); + p != this->section_list_.end(); + ++p) + { + if ((*p)->needs_dynsym_index()) + { + gold_assert(dynsym_section != NULL); + unsigned int index = (*p)->dynsym_index(); + gold_assert(index > 0 && index != -1U); + off_t off = (dynsym_section->offset() + + index * dynsym_section->entsize()); + symtab->write_section_symbol(*p, this->dynsym_xindex_, of, off); + } + } + + // Write out the Output_data which are not in an Output_section. + for (Data_list::const_iterator p = this->special_output_list_.begin(); + p != this->special_output_list_.end(); + ++p) + (*p)->write(of); + + // Write out the Output_data which are not in an Output_section + // and are regenerated in each iteration of relaxation. + for (Data_list::const_iterator p = this->relax_output_list_.begin(); + p != this->relax_output_list_.end(); + ++p) + (*p)->write(of); +} + +// Write out the Output_sections which can only be written after the +// input sections are complete. + +void +Layout::write_sections_after_input_sections(Output_file* of) +{ + // Determine the final section offsets, and thus the final output + // file size. Note we finalize the .shstrab last, to allow the + // after_input_section sections to modify their section-names before + // writing. + if (this->any_postprocessing_sections_) + { + off_t off = this->output_file_size_; + off = this->set_section_offsets(off, POSTPROCESSING_SECTIONS_PASS); + + // Now that we've finalized the names, we can finalize the shstrab. + off = + this->set_section_offsets(off, + STRTAB_AFTER_POSTPROCESSING_SECTIONS_PASS); + + if (off > this->output_file_size_) + { + of->resize(off); + this->output_file_size_ = off; + } + } + + for (Section_list::const_iterator p = this->section_list_.begin(); + p != this->section_list_.end(); + ++p) + { + if ((*p)->after_input_sections()) + (*p)->write(of); + } + + this->section_headers_->write(of); +} + +// Build IDs can be computed as a "flat" sha1 or md5 of a string of bytes, +// or as a "tree" where each chunk of the string is hashed and then those +// hashes are put into a (much smaller) string which is hashed with sha1. +// We compute a checksum over the entire file because that is simplest. + +Task_token* +Layout::queue_build_id_tasks(Workqueue* workqueue, Task_token* build_id_blocker, + Output_file* of) +{ + const size_t filesize = (this->output_file_size() <= 0 ? 0 + : static_cast(this->output_file_size())); + if (this->build_id_note_ != NULL + && strcmp(parameters->options().build_id(), "tree") == 0 + && parameters->options().build_id_chunk_size_for_treehash() > 0 + && filesize > 0 + && (filesize >= + parameters->options().build_id_min_file_size_for_treehash())) + { + static const size_t MD5_OUTPUT_SIZE_IN_BYTES = 16; + const size_t chunk_size = + parameters->options().build_id_chunk_size_for_treehash(); + const size_t num_hashes = ((filesize - 1) / chunk_size) + 1; + Task_token* post_hash_tasks_blocker = new Task_token(true); + post_hash_tasks_blocker->add_blockers(num_hashes); + this->size_of_array_of_hashes_ = num_hashes * MD5_OUTPUT_SIZE_IN_BYTES; + const unsigned char* src = of->get_input_view(0, filesize); + this->input_view_ = src; + unsigned char *dst = new unsigned char[this->size_of_array_of_hashes_]; + this->array_of_hashes_ = dst; + for (size_t i = 0, src_offset = 0; i < num_hashes; + i++, dst += MD5_OUTPUT_SIZE_IN_BYTES, src_offset += chunk_size) + { + size_t size = std::min(chunk_size, filesize - src_offset); + workqueue->queue(new Hash_task(src + src_offset, + size, + dst, + build_id_blocker, + post_hash_tasks_blocker)); + } + return post_hash_tasks_blocker; + } + return build_id_blocker; +} + +// If a tree-style build ID was requested, the parallel part of that computation +// is already done, and the final hash-of-hashes is computed here. For other +// types of build IDs, all the work is done here. + +void +Layout::write_build_id(Output_file* of) const +{ + if (this->build_id_note_ == NULL) + return; + + unsigned char* ov = of->get_output_view(this->build_id_note_->offset(), + this->build_id_note_->data_size()); + + if (this->array_of_hashes_ == NULL) + { + const size_t output_file_size = this->output_file_size(); + const unsigned char* iv = of->get_input_view(0, output_file_size); + const char* style = parameters->options().build_id(); + + // If we get here with style == "tree" then the output must be + // too small for chunking, and we use SHA-1 in that case. + if ((strcmp(style, "sha1") == 0) || (strcmp(style, "tree") == 0)) + sha1_buffer(reinterpret_cast(iv), output_file_size, ov); + else if (strcmp(style, "md5") == 0) + md5_buffer(reinterpret_cast(iv), output_file_size, ov); + else + gold_unreachable(); + + of->free_input_view(0, output_file_size, iv); + } + else + { + // Non-overlapping substrings of the output file have been hashed. + // Compute SHA-1 hash of the hashes. + sha1_buffer(reinterpret_cast(this->array_of_hashes_), + this->size_of_array_of_hashes_, ov); + delete[] this->array_of_hashes_; + of->free_input_view(0, this->output_file_size(), this->input_view_); + } + + of->write_output_view(this->build_id_note_->offset(), + this->build_id_note_->data_size(), + ov); +} + +// Write out a binary file. This is called after the link is +// complete. IN is the temporary output file we used to generate the +// ELF code. We simply walk through the segments, read them from +// their file offset in IN, and write them to their load address in +// the output file. FIXME: with a bit more work, we could support +// S-records and/or Intel hex format here. + +void +Layout::write_binary(Output_file* in) const +{ + gold_assert(parameters->options().oformat_enum() + == General_options::OBJECT_FORMAT_BINARY); + + // Get the size of the binary file. + uint64_t max_load_address = 0; + for (Segment_list::const_iterator p = this->segment_list_.begin(); + p != this->segment_list_.end(); + ++p) + { + if ((*p)->type() == elfcpp::PT_LOAD && (*p)->filesz() > 0) + { + uint64_t max_paddr = (*p)->paddr() + (*p)->filesz(); + if (max_paddr > max_load_address) + max_load_address = max_paddr; + } + } + + Output_file out(parameters->options().output_file_name()); + out.open(max_load_address); + + for (Segment_list::const_iterator p = this->segment_list_.begin(); + p != this->segment_list_.end(); + ++p) + { + if ((*p)->type() == elfcpp::PT_LOAD && (*p)->filesz() > 0) + { + const unsigned char* vin = in->get_input_view((*p)->offset(), + (*p)->filesz()); + unsigned char* vout = out.get_output_view((*p)->paddr(), + (*p)->filesz()); + memcpy(vout, vin, (*p)->filesz()); + out.write_output_view((*p)->paddr(), (*p)->filesz(), vout); + in->free_input_view((*p)->offset(), (*p)->filesz(), vin); + } + } + + out.close(); +} + +// Print the output sections to the map file. + +void +Layout::print_to_mapfile(Mapfile* mapfile) const +{ + for (Segment_list::const_iterator p = this->segment_list_.begin(); + p != this->segment_list_.end(); + ++p) + (*p)->print_sections_to_mapfile(mapfile); +} + +// Print statistical information to stderr. This is used for --stats. + +void +Layout::print_stats() const +{ + this->namepool_.print_stats("section name pool"); + this->sympool_.print_stats("output symbol name pool"); + this->dynpool_.print_stats("dynamic name pool"); + + for (Section_list::const_iterator p = this->section_list_.begin(); + p != this->section_list_.end(); + ++p) + (*p)->print_merge_stats(); +} + +// Write_sections_task methods. + +// We can always run this task. + +Task_token* +Write_sections_task::is_runnable() +{ + return NULL; +} + +// We need to unlock both OUTPUT_SECTIONS_BLOCKER and FINAL_BLOCKER +// when finished. + +void +Write_sections_task::locks(Task_locker* tl) +{ + tl->add(this, this->output_sections_blocker_); + tl->add(this, this->final_blocker_); +} + +// Run the task--write out the data. + +void +Write_sections_task::run(Workqueue*) +{ + this->layout_->write_output_sections(this->of_); +} + +// Write_data_task methods. + +// We can always run this task. + +Task_token* +Write_data_task::is_runnable() +{ + return NULL; +} + +// We need to unlock FINAL_BLOCKER when finished. + +void +Write_data_task::locks(Task_locker* tl) +{ + tl->add(this, this->final_blocker_); +} + +// Run the task--write out the data. + +void +Write_data_task::run(Workqueue*) +{ + this->layout_->write_data(this->symtab_, this->of_); +} + +// Write_symbols_task methods. + +// We can always run this task. + +Task_token* +Write_symbols_task::is_runnable() +{ + return NULL; +} + +// We need to unlock FINAL_BLOCKER when finished. + +void +Write_symbols_task::locks(Task_locker* tl) +{ + tl->add(this, this->final_blocker_); +} + +// Run the task--write out the symbols. + +void +Write_symbols_task::run(Workqueue*) +{ + this->symtab_->write_globals(this->sympool_, this->dynpool_, + this->layout_->symtab_xindex(), + this->layout_->dynsym_xindex(), this->of_); +} + +// Write_after_input_sections_task methods. + +// We can only run this task after the input sections have completed. + +Task_token* +Write_after_input_sections_task::is_runnable() +{ + if (this->input_sections_blocker_->is_blocked()) + return this->input_sections_blocker_; + return NULL; +} + +// We need to unlock FINAL_BLOCKER when finished. + +void +Write_after_input_sections_task::locks(Task_locker* tl) +{ + tl->add(this, this->final_blocker_); +} + +// Run the task. + +void +Write_after_input_sections_task::run(Workqueue*) +{ + this->layout_->write_sections_after_input_sections(this->of_); +} + +// Close_task_runner methods. + +// Finish up the build ID computation, if necessary, and write a binary file, +// if necessary. Then close the output file. + +void +Close_task_runner::run(Workqueue*, const Task*) +{ + // At this point the multi-threaded part of the build ID computation, + // if any, is done. See queue_build_id_tasks(). + this->layout_->write_build_id(this->of_); + + // If we've been asked to create a binary file, we do so here. + if (this->options_->oformat_enum() != General_options::OBJECT_FORMAT_ELF) + this->layout_->write_binary(this->of_); + + this->of_->close(); +} + +// Instantiate the templates we need. We could use the configure +// script to restrict this to only the ones for implemented targets. + +#ifdef HAVE_TARGET_32_LITTLE +template +Output_section* +Layout::init_fixed_output_section<32, false>( + const char* name, + elfcpp::Shdr<32, false>& shdr); +#endif + +#ifdef HAVE_TARGET_32_BIG +template +Output_section* +Layout::init_fixed_output_section<32, true>( + const char* name, + elfcpp::Shdr<32, true>& shdr); +#endif + +#ifdef HAVE_TARGET_64_LITTLE +template +Output_section* +Layout::init_fixed_output_section<64, false>( + const char* name, + elfcpp::Shdr<64, false>& shdr); +#endif + +#ifdef HAVE_TARGET_64_BIG +template +Output_section* +Layout::init_fixed_output_section<64, true>( + const char* name, + elfcpp::Shdr<64, true>& shdr); +#endif + +#ifdef HAVE_TARGET_32_LITTLE +template +Output_section* +Layout::layout<32, false>(Sized_relobj_file<32, false>* object, + unsigned int shndx, + const char* name, + const elfcpp::Shdr<32, false>& shdr, + unsigned int, unsigned int, off_t*); +#endif + +#ifdef HAVE_TARGET_32_BIG +template +Output_section* +Layout::layout<32, true>(Sized_relobj_file<32, true>* object, + unsigned int shndx, + const char* name, + const elfcpp::Shdr<32, true>& shdr, + unsigned int, unsigned int, off_t*); +#endif + +#ifdef HAVE_TARGET_64_LITTLE +template +Output_section* +Layout::layout<64, false>(Sized_relobj_file<64, false>* object, + unsigned int shndx, + const char* name, + const elfcpp::Shdr<64, false>& shdr, + unsigned int, unsigned int, off_t*); +#endif + +#ifdef HAVE_TARGET_64_BIG +template +Output_section* +Layout::layout<64, true>(Sized_relobj_file<64, true>* object, + unsigned int shndx, + const char* name, + const elfcpp::Shdr<64, true>& shdr, + unsigned int, unsigned int, off_t*); +#endif + +#ifdef HAVE_TARGET_32_LITTLE +template +Output_section* +Layout::layout_reloc<32, false>(Sized_relobj_file<32, false>* object, + unsigned int reloc_shndx, + const elfcpp::Shdr<32, false>& shdr, + Output_section* data_section, + Relocatable_relocs* rr); +#endif + +#ifdef HAVE_TARGET_32_BIG +template +Output_section* +Layout::layout_reloc<32, true>(Sized_relobj_file<32, true>* object, + unsigned int reloc_shndx, + const elfcpp::Shdr<32, true>& shdr, + Output_section* data_section, + Relocatable_relocs* rr); +#endif + +#ifdef HAVE_TARGET_64_LITTLE +template +Output_section* +Layout::layout_reloc<64, false>(Sized_relobj_file<64, false>* object, + unsigned int reloc_shndx, + const elfcpp::Shdr<64, false>& shdr, + Output_section* data_section, + Relocatable_relocs* rr); +#endif + +#ifdef HAVE_TARGET_64_BIG +template +Output_section* +Layout::layout_reloc<64, true>(Sized_relobj_file<64, true>* object, + unsigned int reloc_shndx, + const elfcpp::Shdr<64, true>& shdr, + Output_section* data_section, + Relocatable_relocs* rr); +#endif + +#ifdef HAVE_TARGET_32_LITTLE +template +void +Layout::layout_group<32, false>(Symbol_table* symtab, + Sized_relobj_file<32, false>* object, + unsigned int, + const char* group_section_name, + const char* signature, + const elfcpp::Shdr<32, false>& shdr, + elfcpp::Elf_Word flags, + std::vector* shndxes); +#endif + +#ifdef HAVE_TARGET_32_BIG +template +void +Layout::layout_group<32, true>(Symbol_table* symtab, + Sized_relobj_file<32, true>* object, + unsigned int, + const char* group_section_name, + const char* signature, + const elfcpp::Shdr<32, true>& shdr, + elfcpp::Elf_Word flags, + std::vector* shndxes); +#endif + +#ifdef HAVE_TARGET_64_LITTLE +template +void +Layout::layout_group<64, false>(Symbol_table* symtab, + Sized_relobj_file<64, false>* object, + unsigned int, + const char* group_section_name, + const char* signature, + const elfcpp::Shdr<64, false>& shdr, + elfcpp::Elf_Word flags, + std::vector* shndxes); +#endif + +#ifdef HAVE_TARGET_64_BIG +template +void +Layout::layout_group<64, true>(Symbol_table* symtab, + Sized_relobj_file<64, true>* object, + unsigned int, + const char* group_section_name, + const char* signature, + const elfcpp::Shdr<64, true>& shdr, + elfcpp::Elf_Word flags, + std::vector* shndxes); +#endif + +#ifdef HAVE_TARGET_32_LITTLE +template +Output_section* +Layout::layout_eh_frame<32, false>(Sized_relobj_file<32, false>* object, + const unsigned char* symbols, + off_t symbols_size, + const unsigned char* symbol_names, + off_t symbol_names_size, + unsigned int shndx, + const elfcpp::Shdr<32, false>& shdr, + unsigned int reloc_shndx, + unsigned int reloc_type, + off_t* off); +#endif + +#ifdef HAVE_TARGET_32_BIG +template +Output_section* +Layout::layout_eh_frame<32, true>(Sized_relobj_file<32, true>* object, + const unsigned char* symbols, + off_t symbols_size, + const unsigned char* symbol_names, + off_t symbol_names_size, + unsigned int shndx, + const elfcpp::Shdr<32, true>& shdr, + unsigned int reloc_shndx, + unsigned int reloc_type, + off_t* off); +#endif + +#ifdef HAVE_TARGET_64_LITTLE +template +Output_section* +Layout::layout_eh_frame<64, false>(Sized_relobj_file<64, false>* object, + const unsigned char* symbols, + off_t symbols_size, + const unsigned char* symbol_names, + off_t symbol_names_size, + unsigned int shndx, + const elfcpp::Shdr<64, false>& shdr, + unsigned int reloc_shndx, + unsigned int reloc_type, + off_t* off); +#endif + +#ifdef HAVE_TARGET_64_BIG +template +Output_section* +Layout::layout_eh_frame<64, true>(Sized_relobj_file<64, true>* object, + const unsigned char* symbols, + off_t symbols_size, + const unsigned char* symbol_names, + off_t symbol_names_size, + unsigned int shndx, + const elfcpp::Shdr<64, true>& shdr, + unsigned int reloc_shndx, + unsigned int reloc_type, + off_t* off); +#endif + +#ifdef HAVE_TARGET_32_LITTLE +template +void +Layout::add_to_gdb_index(bool is_type_unit, + Sized_relobj<32, false>* object, + const unsigned char* symbols, + off_t symbols_size, + unsigned int shndx, + unsigned int reloc_shndx, + unsigned int reloc_type); +#endif + +#ifdef HAVE_TARGET_32_BIG +template +void +Layout::add_to_gdb_index(bool is_type_unit, + Sized_relobj<32, true>* object, + const unsigned char* symbols, + off_t symbols_size, + unsigned int shndx, + unsigned int reloc_shndx, + unsigned int reloc_type); +#endif + +#ifdef HAVE_TARGET_64_LITTLE +template +void +Layout::add_to_gdb_index(bool is_type_unit, + Sized_relobj<64, false>* object, + const unsigned char* symbols, + off_t symbols_size, + unsigned int shndx, + unsigned int reloc_shndx, + unsigned int reloc_type); +#endif + +#ifdef HAVE_TARGET_64_BIG +template +void +Layout::add_to_gdb_index(bool is_type_unit, + Sized_relobj<64, true>* object, + const unsigned char* symbols, + off_t symbols_size, + unsigned int shndx, + unsigned int reloc_shndx, + unsigned int reloc_type); +#endif + +} // End namespace gold. diff --git a/binutils-2.25/gold/layout.h b/binutils-2.25/gold/layout.h new file mode 100644 index 00000000..792b748d --- /dev/null +++ b/binutils-2.25/gold/layout.h @@ -0,0 +1,1629 @@ +// layout.h -- lay out output file sections for gold -*- C++ -*- + +// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 +// Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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. + +#ifndef GOLD_LAYOUT_H +#define GOLD_LAYOUT_H + +#include +#include +#include +#include +#include +#include + +#include "script.h" +#include "workqueue.h" +#include "object.h" +#include "dynobj.h" +#include "stringpool.h" + +namespace gold +{ + +class General_options; +class Incremental_inputs; +class Incremental_binary; +class Input_objects; +class Mapfile; +class Symbol_table; +class Output_section_data; +class Output_section; +class Output_section_headers; +class Output_segment_headers; +class Output_file_header; +class Output_segment; +class Output_data; +class Output_data_reloc_generic; +class Output_data_dynamic; +class Output_symtab_xindex; +class Output_reduced_debug_abbrev_section; +class Output_reduced_debug_info_section; +class Eh_frame; +class Gdb_index; +class Target; +struct Timespec; + +// Return TRUE if SECNAME is the name of a compressed debug section. +extern bool +is_compressed_debug_section(const char* secname); + +// Maintain a list of free space within a section, segment, or file. +// Used for incremental update links. + +class Free_list +{ + public: + struct Free_list_node + { + Free_list_node(off_t start, off_t end) + : start_(start), end_(end) + { } + off_t start_; + off_t end_; + }; + typedef std::list::const_iterator Const_iterator; + + Free_list() + : list_(), last_remove_(list_.begin()), extend_(false), length_(0), + min_hole_(0) + { } + + // Initialize the free list for a section of length LEN. + // If EXTEND is true, free space may be allocated past the end. + void + init(off_t len, bool extend); + + // Set the minimum hole size that is allowed when allocating + // from the free list. + void + set_min_hole_size(off_t min_hole) + { this->min_hole_ = min_hole; } + + // Remove a chunk from the free list. + void + remove(off_t start, off_t end); + + // Allocate a chunk of space from the free list of length LEN, + // with alignment ALIGN, and minimum offset MINOFF. + off_t + allocate(off_t len, uint64_t align, off_t minoff); + + // Return an iterator for the beginning of the free list. + Const_iterator + begin() const + { return this->list_.begin(); } + + // Return an iterator for the end of the free list. + Const_iterator + end() const + { return this->list_.end(); } + + // Dump the free list (for debugging). + void + dump(); + + // Print usage statistics. + static void + print_stats(); + + private: + typedef std::list::iterator Iterator; + + // The free list. + std::list list_; + + // The last node visited during a remove operation. + Iterator last_remove_; + + // Whether we can extend past the original length. + bool extend_; + + // The total length of the section, segment, or file. + off_t length_; + + // The minimum hole size allowed. When allocating from the free list, + // we must not leave a hole smaller than this. + off_t min_hole_; + + // Statistics: + // The total number of free lists used. + static unsigned int num_lists; + // The total number of free list nodes used. + static unsigned int num_nodes; + // The total number of calls to Free_list::remove. + static unsigned int num_removes; + // The total number of nodes visited during calls to Free_list::remove. + static unsigned int num_remove_visits; + // The total number of calls to Free_list::allocate. + static unsigned int num_allocates; + // The total number of nodes visited during calls to Free_list::allocate. + static unsigned int num_allocate_visits; +}; + +// This task function handles mapping the input sections to output +// sections and laying them out in memory. + +class Layout_task_runner : public Task_function_runner +{ + public: + // OPTIONS is the command line options, INPUT_OBJECTS is the list of + // input objects, SYMTAB is the symbol table, LAYOUT is the layout + // object. + Layout_task_runner(const General_options& options, + const Input_objects* input_objects, + Symbol_table* symtab, + Target* target, + Layout* layout, + Mapfile* mapfile) + : options_(options), input_objects_(input_objects), symtab_(symtab), + target_(target), layout_(layout), mapfile_(mapfile) + { } + + // Run the operation. + void + run(Workqueue*, const Task*); + + private: + Layout_task_runner(const Layout_task_runner&); + Layout_task_runner& operator=(const Layout_task_runner&); + + const General_options& options_; + const Input_objects* input_objects_; + Symbol_table* symtab_; + Target* target_; + Layout* layout_; + Mapfile* mapfile_; +}; + +// This class holds information about the comdat group or +// .gnu.linkonce section that will be kept for a given signature. + +class Kept_section +{ + private: + // For a comdat group, we build a mapping from the name of each + // section in the group to the section index and the size in object. + // When we discard a group in some other object file, we use this + // map to figure out which kept section the discarded section is + // associated with. We then use that mapping when processing relocs + // against discarded sections. + struct Comdat_section_info + { + // The section index. + unsigned int shndx; + // The section size. + uint64_t size; + + Comdat_section_info(unsigned int a_shndx, uint64_t a_size) + : shndx(a_shndx), size(a_size) + { } + }; + + // Most comdat groups have only one or two sections, so we use a + // std::map rather than an Unordered_map to optimize for that case + // without paying too heavily for groups with more sections. + typedef std::map Comdat_group; + + public: + Kept_section() + : object_(NULL), shndx_(0), is_comdat_(false), is_group_name_(false) + { this->u_.linkonce_size = 0; } + + // We need to support copies for the signature map in the Layout + // object, but we should never copy an object after it has been + // marked as a comdat section. + Kept_section(const Kept_section& k) + : object_(k.object_), shndx_(k.shndx_), is_comdat_(false), + is_group_name_(k.is_group_name_) + { + gold_assert(!k.is_comdat_); + this->u_.linkonce_size = 0; + } + + ~Kept_section() + { + if (this->is_comdat_) + delete this->u_.group_sections; + } + + // The object where this section lives. + Relobj* + object() const + { return this->object_; } + + // Set the object. + void + set_object(Relobj* object) + { + gold_assert(this->object_ == NULL); + this->object_ = object; + } + + // The section index. + unsigned int + shndx() const + { return this->shndx_; } + + // Set the section index. + void + set_shndx(unsigned int shndx) + { + gold_assert(this->shndx_ == 0); + this->shndx_ = shndx; + } + + // Whether this is a comdat group. + bool + is_comdat() const + { return this->is_comdat_; } + + // Set that this is a comdat group. + void + set_is_comdat() + { + gold_assert(!this->is_comdat_); + this->is_comdat_ = true; + this->u_.group_sections = new Comdat_group(); + } + + // Whether this is associated with the name of a group or section + // rather than the symbol name derived from a linkonce section. + bool + is_group_name() const + { return this->is_group_name_; } + + // Note that this represents a comdat group rather than a single + // linkonce section. + void + set_is_group_name() + { this->is_group_name_ = true; } + + // Add a section to the group list. + void + add_comdat_section(const std::string& name, unsigned int shndx, + uint64_t size) + { + gold_assert(this->is_comdat_); + Comdat_section_info sinfo(shndx, size); + this->u_.group_sections->insert(std::make_pair(name, sinfo)); + } + + // Look for a section name in the group list, and return whether it + // was found. If found, returns the section index and size. + bool + find_comdat_section(const std::string& name, unsigned int* pshndx, + uint64_t* psize) const + { + gold_assert(this->is_comdat_); + Comdat_group::const_iterator p = this->u_.group_sections->find(name); + if (p == this->u_.group_sections->end()) + return false; + *pshndx = p->second.shndx; + *psize = p->second.size; + return true; + } + + // If there is only one section in the group list, return true, and + // return the section index and size. + bool + find_single_comdat_section(unsigned int* pshndx, uint64_t* psize) const + { + gold_assert(this->is_comdat_); + if (this->u_.group_sections->size() != 1) + return false; + Comdat_group::const_iterator p = this->u_.group_sections->begin(); + *pshndx = p->second.shndx; + *psize = p->second.size; + return true; + } + + // Return the size of a linkonce section. + uint64_t + linkonce_size() const + { + gold_assert(!this->is_comdat_); + return this->u_.linkonce_size; + } + + // Set the size of a linkonce section. + void + set_linkonce_size(uint64_t size) + { + gold_assert(!this->is_comdat_); + this->u_.linkonce_size = size; + } + + private: + // No assignment. + Kept_section& operator=(const Kept_section&); + + // The object containing the comdat group or .gnu.linkonce section. + Relobj* object_; + // Index of the group section for comdats and the section itself for + // .gnu.linkonce. + unsigned int shndx_; + // True if this is for a comdat group rather than a .gnu.linkonce + // section. + bool is_comdat_; + // The Kept_sections are values of a mapping, that maps names to + // them. This field is true if this struct is associated with the + // name of a comdat or .gnu.linkonce, false if it is associated with + // the name of a symbol obtained from the .gnu.linkonce.* name + // through some heuristics. + bool is_group_name_; + union + { + // If the is_comdat_ field is true, this holds a map from names of + // the sections in the group to section indexes in object_ and to + // section sizes. + Comdat_group* group_sections; + // If the is_comdat_ field is false, this holds the size of the + // single section. + uint64_t linkonce_size; + } u_; +}; + +// The ordering for output sections. This controls how output +// sections are ordered within a PT_LOAD output segment. + +enum Output_section_order +{ + // Unspecified. Used for non-load segments. Also used for the file + // and segment headers. + ORDER_INVALID, + + // The PT_INTERP section should come first, so that the dynamic + // linker can pick it up quickly. + ORDER_INTERP, + + // Loadable read-only note sections come next so that the PT_NOTE + // segment is on the first page of the executable. + ORDER_RO_NOTE, + + // Put read-only sections used by the dynamic linker early in the + // executable to minimize paging. + ORDER_DYNAMIC_LINKER, + + // Put reloc sections used by the dynamic linker after other + // sections used by the dynamic linker; otherwise, objcopy and strip + // get confused. + ORDER_DYNAMIC_RELOCS, + + // Put the PLT reloc section after the other dynamic relocs; + // otherwise, prelink gets confused. + ORDER_DYNAMIC_PLT_RELOCS, + + // The .init section. + ORDER_INIT, + + // The PLT. + ORDER_PLT, + + // The regular text sections. + ORDER_TEXT, + + // The .fini section. + ORDER_FINI, + + // The read-only sections. + ORDER_READONLY, + + // The exception frame sections. + ORDER_EHFRAME, + + // The TLS sections come first in the data section. + ORDER_TLS_DATA, + ORDER_TLS_BSS, + + // Local RELRO (read-only after relocation) sections come before + // non-local RELRO sections. This data will be fully resolved by + // the prelinker. + ORDER_RELRO_LOCAL, + + // Non-local RELRO sections are grouped together after local RELRO + // sections. All RELRO sections must be adjacent so that they can + // all be put into a PT_GNU_RELRO segment. + ORDER_RELRO, + + // We permit marking exactly one output section as the last RELRO + // section. We do this so that the read-only GOT can be adjacent to + // the writable GOT. + ORDER_RELRO_LAST, + + // Similarly, we permit marking exactly one output section as the + // first non-RELRO section. + ORDER_NON_RELRO_FIRST, + + // The regular data sections come after the RELRO sections. + ORDER_DATA, + + // Large data sections normally go in large data segments. + ORDER_LARGE_DATA, + + // Group writable notes so that we can have a single PT_NOTE + // segment. + ORDER_RW_NOTE, + + // The small data sections must be at the end of the data sections, + // so that they can be adjacent to the small BSS sections. + ORDER_SMALL_DATA, + + // The BSS sections start here. + + // The small BSS sections must be at the start of the BSS sections, + // so that they can be adjacent to the small data sections. + ORDER_SMALL_BSS, + + // The regular BSS sections. + ORDER_BSS, + + // The large BSS sections come after the other BSS sections. + ORDER_LARGE_BSS, + + // Maximum value. + ORDER_MAX +}; + +// This class handles the details of laying out input sections. + +class Layout +{ + public: + Layout(int number_of_input_files, Script_options*); + + ~Layout() + { + delete this->relaxation_debug_check_; + delete this->segment_states_; + } + + // For incremental links, record the base file to be modified. + void + set_incremental_base(Incremental_binary* base); + + Incremental_binary* + incremental_base() + { return this->incremental_base_; } + + // For incremental links, record the initial fixed layout of a section + // from the base file, and return a pointer to the Output_section. + template + Output_section* + init_fixed_output_section(const char*, elfcpp::Shdr&); + + // Given an input section SHNDX, named NAME, with data in SHDR, from + // the object file OBJECT, return the output section where this + // input section should go. RELOC_SHNDX is the index of a + // relocation section which applies to this section, or 0 if none, + // or -1U if more than one. RELOC_TYPE is the type of the + // relocation section if there is one. Set *OFFSET to the offset + // within the output section. + template + Output_section* + layout(Sized_relobj_file *object, unsigned int shndx, + const char* name, const elfcpp::Shdr& shdr, + unsigned int reloc_shndx, unsigned int reloc_type, off_t* offset); + + std::map* + get_section_order_map() + { return &this->section_order_map_; } + + // Struct to store segment info when mapping some input sections to + // unique segments using linker plugins. Mapping an input section to + // a unique segment is done by first placing such input sections in + // unique output sections and then mapping the output section to a + // unique segment. NAME is the name of the output section. FLAGS + // and ALIGN are the extra flags and alignment of the segment. + struct Unique_segment_info + { + // Identifier for the segment. ELF segments dont have names. This + // is used as the name of the output section mapped to the segment. + const char* name; + // Additional segment flags. + uint64_t flags; + // Segment alignment. + uint64_t align; + }; + + // Mapping from input section to segment. + typedef std::map + Section_segment_map; + + // Maps section SECN to SEGMENT s. + void + insert_section_segment_map(Const_section_id secn, Unique_segment_info *s); + + // Some input sections require special ordering, for compatibility + // with GNU ld. Given the name of an input section, return -1 if it + // does not require special ordering. Otherwise, return the index + // by which it should be ordered compared to other input sections + // that require special ordering. + static int + special_ordering_of_input_section(const char* name); + + bool + is_section_ordering_specified() + { return this->section_ordering_specified_; } + + void + set_section_ordering_specified() + { this->section_ordering_specified_ = true; } + + bool + is_unique_segment_for_sections_specified() const + { return this->unique_segment_for_sections_specified_; } + + void + set_unique_segment_for_sections_specified() + { this->unique_segment_for_sections_specified_ = true; } + + // For incremental updates, allocate a block of memory from the + // free list. Find a block starting at or after MINOFF. + off_t + allocate(off_t len, uint64_t align, off_t minoff) + { return this->free_list_.allocate(len, align, minoff); } + + unsigned int + find_section_order_index(const std::string&); + + // Read the sequence of input sections from the file specified with + // linker option --section-ordering-file. + void + read_layout_from_file(); + + // Layout an input reloc section when doing a relocatable link. The + // section is RELOC_SHNDX in OBJECT, with data in SHDR. + // DATA_SECTION is the reloc section to which it refers. RR is the + // relocatable information. + template + Output_section* + layout_reloc(Sized_relobj_file* object, + unsigned int reloc_shndx, + const elfcpp::Shdr& shdr, + Output_section* data_section, + Relocatable_relocs* rr); + + // Layout a group section when doing a relocatable link. + template + void + layout_group(Symbol_table* symtab, + Sized_relobj_file* object, + unsigned int group_shndx, + const char* group_section_name, + const char* signature, + const elfcpp::Shdr& shdr, + elfcpp::Elf_Word flags, + std::vector* shndxes); + + // Like layout, only for exception frame sections. OBJECT is an + // object file. SYMBOLS is the contents of the symbol table + // section, with size SYMBOLS_SIZE. SYMBOL_NAMES is the contents of + // the symbol name section, with size SYMBOL_NAMES_SIZE. SHNDX is a + // .eh_frame section in OBJECT. SHDR is the section header. + // RELOC_SHNDX is the index of a relocation section which applies to + // this section, or 0 if none, or -1U if more than one. RELOC_TYPE + // is the type of the relocation section if there is one. This + // returns the output section, and sets *OFFSET to the offset. + template + Output_section* + layout_eh_frame(Sized_relobj_file* object, + const unsigned char* symbols, + off_t symbols_size, + const unsigned char* symbol_names, + off_t symbol_names_size, + unsigned int shndx, + const elfcpp::Shdr& shdr, + unsigned int reloc_shndx, unsigned int reloc_type, + off_t* offset); + + // Add .eh_frame information for a PLT. The FDE must start with a + // 4-byte PC-relative reference to the start of the PLT, followed by + // a 4-byte size of PLT. + void + add_eh_frame_for_plt(Output_data* plt, const unsigned char* cie_data, + size_t cie_length, const unsigned char* fde_data, + size_t fde_length); + + // Scan a .debug_info or .debug_types section, and add summary + // information to the .gdb_index section. + template + void + add_to_gdb_index(bool is_type_unit, + Sized_relobj* object, + const unsigned char* symbols, + off_t symbols_size, + unsigned int shndx, + unsigned int reloc_shndx, + unsigned int reloc_type); + + // Handle a GNU stack note. This is called once per input object + // file. SEEN_GNU_STACK is true if the object file has a + // .note.GNU-stack section. GNU_STACK_FLAGS is the section flags + // from that section if there was one. + void + layout_gnu_stack(bool seen_gnu_stack, uint64_t gnu_stack_flags, + const Object*); + + // Add an Output_section_data to the layout. This is used for + // special sections like the GOT section. ORDER is where the + // section should wind up in the output segment. IS_RELRO is true + // for relro sections. + Output_section* + add_output_section_data(const char* name, elfcpp::Elf_Word type, + elfcpp::Elf_Xword flags, + Output_section_data*, Output_section_order order, + bool is_relro); + + // Increase the size of the relro segment by this much. + void + increase_relro(unsigned int s) + { this->increase_relro_ += s; } + + // Create dynamic sections if necessary. + void + create_initial_dynamic_sections(Symbol_table*); + + // Define __start and __stop symbols for output sections. + void + define_section_symbols(Symbol_table*); + + // Create automatic note sections. + void + create_notes(); + + // Create sections for linker scripts. + void + create_script_sections() + { this->script_options_->create_script_sections(this); } + + // Define symbols from any linker script. + void + define_script_symbols(Symbol_table* symtab) + { this->script_options_->add_symbols_to_table(symtab); } + + // Define symbols for group signatures. + void + define_group_signatures(Symbol_table*); + + // Return the Stringpool used for symbol names. + const Stringpool* + sympool() const + { return &this->sympool_; } + + // Return the Stringpool used for dynamic symbol names and dynamic + // tags. + const Stringpool* + dynpool() const + { return &this->dynpool_; } + + // Return the .dynamic output section. This is only valid after the + // layout has been finalized. + Output_section* + dynamic_section() const + { return this->dynamic_section_; } + + // Return the symtab_xindex section used to hold large section + // indexes for the normal symbol table. + Output_symtab_xindex* + symtab_xindex() const + { return this->symtab_xindex_; } + + // Return the dynsym_xindex section used to hold large section + // indexes for the dynamic symbol table. + Output_symtab_xindex* + dynsym_xindex() const + { return this->dynsym_xindex_; } + + // Return whether a section is a .gnu.linkonce section, given the + // section name. + static inline bool + is_linkonce(const char* name) + { return strncmp(name, ".gnu.linkonce", sizeof(".gnu.linkonce") - 1) == 0; } + + // Whether we have added an input section. + bool + have_added_input_section() const + { return this->have_added_input_section_; } + + // Return true if a section is a debugging section. + static inline bool + is_debug_info_section(const char* name) + { + // 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); + } + + // Return true if RELOBJ is an input file whose base name matches + // FILE_NAME. The base name must have an extension of ".o", and + // must be exactly FILE_NAME.o or FILE_NAME, one character, ".o". + static bool + match_file_name(const Relobj* relobj, const char* file_name); + + // Return whether section SHNDX in RELOBJ is a .ctors/.dtors section + // with more than one word being mapped to a .init_array/.fini_array + // section. + bool + is_ctors_in_init_array(Relobj* relobj, unsigned int shndx) const; + + // Check if a comdat group or .gnu.linkonce section with the given + // NAME is selected for the link. If there is already a section, + // *KEPT_SECTION is set to point to the signature and the function + // returns false. Otherwise, OBJECT, SHNDX,IS_COMDAT, and + // IS_GROUP_NAME are recorded for this NAME in the layout object, + // *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, + unsigned int shndx, bool is_comdat, + bool is_group_name, Kept_section** kept_section); + + // Finalize the layout after all the input sections have been added. + off_t + finalize(const Input_objects*, Symbol_table*, Target*, const Task*); + + // Return whether any sections require postprocessing. + bool + any_postprocessing_sections() const + { return this->any_postprocessing_sections_; } + + // Return the size of the output file. + off_t + output_file_size() const + { return this->output_file_size_; } + + // Return the TLS segment. This will return NULL if there isn't + // one. + Output_segment* + tls_segment() const + { return this->tls_segment_; } + + // Return the normal symbol table. + Output_section* + symtab_section() const + { + gold_assert(this->symtab_section_ != NULL); + return this->symtab_section_; + } + + // Return the file offset of the normal symbol table. + off_t + symtab_section_offset() const; + + // Return the section index of the normal symbol tabl.e + unsigned int + symtab_section_shndx() const; + + // Return the dynamic symbol table. + Output_section* + dynsym_section() const + { + gold_assert(this->dynsym_section_ != NULL); + return this->dynsym_section_; + } + + // Return the dynamic tags. + Output_data_dynamic* + dynamic_data() const + { return this->dynamic_data_; } + + // Write out the output sections. + void + write_output_sections(Output_file* of) const; + + // Write out data not associated with an input file or the symbol + // table. + void + write_data(const Symbol_table*, Output_file*) const; + + // Write out output sections which can not be written until all the + // input sections are complete. + void + write_sections_after_input_sections(Output_file* of); + + // Return an output section named NAME, or NULL if there is none. + Output_section* + find_output_section(const char* name) const; + + // Return an output segment of type TYPE, with segment flags SET set + // and segment flags CLEAR clear. Return NULL if there is none. + Output_segment* + find_output_segment(elfcpp::PT type, elfcpp::Elf_Word set, + elfcpp::Elf_Word clear) const; + + // Return the number of segments we expect to produce. + size_t + expected_segment_count() const; + + // Set a flag to indicate that an object file uses the static TLS model. + void + set_has_static_tls() + { this->has_static_tls_ = true; } + + // Return true if any object file uses the static TLS model. + bool + has_static_tls() const + { return this->has_static_tls_; } + + // Return the options which may be set by a linker script. + Script_options* + script_options() + { return this->script_options_; } + + const Script_options* + script_options() const + { return this->script_options_; } + + // Return the object managing inputs in incremental build. NULL in + // non-incremental builds. + Incremental_inputs* + incremental_inputs() const + { return this->incremental_inputs_; } + + // For the target-specific code to add dynamic tags which are common + // to most targets. + void + add_target_dynamic_tags(bool use_rel, const Output_data* plt_got, + const Output_data* plt_rel, + const Output_data_reloc_generic* dyn_rel, + bool add_debug, bool dynrel_includes_plt); + + // If a treehash is necessary to compute the build ID, then queue + // the necessary tasks and return a blocker that will unblock when + // they finish. Otherwise return BUILD_ID_BLOCKER. + Task_token* + queue_build_id_tasks(Workqueue* workqueue, Task_token* build_id_blocker, + Output_file* of); + + // Compute and write out the build ID if needed. + void + write_build_id(Output_file*) const; + + // Rewrite output file in binary format. + void + write_binary(Output_file* in) const; + + // Print output sections to the map file. + void + print_to_mapfile(Mapfile*) const; + + // Dump statistical information to stderr. + void + print_stats() const; + + // A list of segments. + + typedef std::vector Segment_list; + + // A list of sections. + + typedef std::vector Section_list; + + // The list of information to write out which is not attached to + // either a section or a segment. + typedef std::vector Data_list; + + // Store the allocated sections into the section list. This is used + // by the linker script code. + void + get_allocated_sections(Section_list*) const; + + // Store the executable sections into the section list. + void + get_executable_sections(Section_list*) const; + + // Make a section for a linker script to hold data. + Output_section* + make_output_section_for_script(const char* name, + Script_sections::Section_type section_type); + + // Make a segment. This is used by the linker script code. + Output_segment* + make_output_segment(elfcpp::Elf_Word type, elfcpp::Elf_Word flags); + + // Return the number of segments. + size_t + segment_count() const + { return this->segment_list_.size(); } + + // Map from section flags to segment flags. + static elfcpp::Elf_Word + section_flags_to_segment(elfcpp::Elf_Xword flags); + + // Attach sections to segments. + void + attach_sections_to_segments(const Target*); + + // For relaxation clean up, we need to know output section data created + // from a linker script. + void + new_output_section_data_from_script(Output_section_data* posd) + { + if (this->record_output_section_data_from_script_) + this->script_output_section_data_list_.push_back(posd); + } + + // Return section list. + const Section_list& + section_list() const + { return this->section_list_; } + + // Returns TRUE iff NAME (an input section from RELOBJ) will + // be mapped to an output section that should be KEPT. + bool + keep_input_section(const Relobj*, const char*); + + // Add a special output object that will be recreated afresh + // if there is another relaxation iteration. + void + add_relax_output(Output_data* data) + { this->relax_output_list_.push_back(data); } + + // Clear out (and free) everything added by add_relax_output. + void + reset_relax_output(); + + private: + Layout(const Layout&); + Layout& operator=(const Layout&); + + // Mapping from input section names to output section names. + struct Section_name_mapping + { + const char* from; + int fromlen; + const char* to; + int tolen; + }; + static const Section_name_mapping section_name_mapping[]; + static const int section_name_mapping_count; + + // During a relocatable link, a list of group sections and + // signatures. + struct Group_signature + { + // The group section. + Output_section* section; + // The signature. + const char* signature; + + Group_signature() + : section(NULL), signature(NULL) + { } + + Group_signature(Output_section* sectiona, const char* signaturea) + : section(sectiona), signature(signaturea) + { } + }; + typedef std::vector Group_signatures; + + // Create a note section, filling in the header. + Output_section* + create_note(const char* name, int note_type, const char* section_name, + size_t descsz, bool allocate, size_t* trailing_padding); + + // Create a note section for gold version. + void + create_gold_note(); + + // Record whether the stack must be executable. + void + create_executable_stack_info(); + + // Create a build ID note if needed. + void + create_build_id(); + + // Link .stab and .stabstr sections. + void + link_stabs_sections(); + + // Create .gnu_incremental_inputs and .gnu_incremental_strtab sections needed + // for the next run of incremental linking to check what has changed. + void + create_incremental_info_sections(Symbol_table*); + + // Find the first read-only PT_LOAD segment, creating one if + // necessary. + Output_segment* + 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. + void + count_local_symbols(const Task*, const Input_objects*); + + // Create the output sections for the symbol table. + void + create_symtab_sections(const Input_objects*, Symbol_table*, + unsigned int, off_t*); + + // Create the .shstrtab section. + Output_section* + create_shstrtab(); + + // Create the section header table. + void + create_shdrs(const Output_section* shstrtab_section, off_t*); + + // Create the dynamic symbol table. + void + create_dynamic_symtab(const Input_objects*, Symbol_table*, + Output_section** pdynstr, + unsigned int* plocal_dynamic_count, + std::vector* pdynamic_symbols, + Versions* versions); + + // Assign offsets to each local portion of the dynamic symbol table. + void + assign_local_dynsym_offsets(const Input_objects*); + + // Finish the .dynamic section and PT_DYNAMIC segment. + void + finish_dynamic_section(const Input_objects*, const Symbol_table*); + + // Set the size of the _DYNAMIC symbol. + void + set_dynamic_symbol_size(const Symbol_table*); + + // Create the .interp section and PT_INTERP segment. + void + create_interp(const Target* target); + + // Create the version sections. + void + create_version_sections(const Versions*, + const Symbol_table*, + unsigned int local_symcount, + const std::vector& dynamic_symbols, + const Output_section* dynstr); + + template + void + sized_create_version_sections(const Versions* versions, + const Symbol_table*, + unsigned int local_symcount, + const std::vector& dynamic_symbols, + const Output_section* dynstr); + + // Return whether to include this section in the link. + template + bool + include_section(Sized_relobj_file* object, const char* name, + const elfcpp::Shdr&); + + // Return the output section name to use given an input section + // name. Set *PLEN to the length of the name. *PLEN must be + // initialized to the length of NAME. + static const char* + output_section_name(const Relobj*, const char* name, size_t* plen); + + // Return the number of allocated output sections. + size_t + allocated_output_section_count() const; + + // Return the output section for NAME, TYPE and FLAGS. + Output_section* + get_output_section(const char* name, Stringpool::Key name_key, + elfcpp::Elf_Word type, elfcpp::Elf_Xword flags, + Output_section_order order, bool is_relro); + + // Clear the input section flags that should not be copied to the + // output section. + elfcpp::Elf_Xword + get_output_section_flags (elfcpp::Elf_Xword input_section_flags); + + // Choose the output section for NAME in RELOBJ. + Output_section* + choose_output_section(const Relobj* relobj, const char* name, + elfcpp::Elf_Word type, elfcpp::Elf_Xword flags, + bool is_input_section, Output_section_order order, + bool is_relro); + + // Create a new Output_section. + Output_section* + make_output_section(const char* name, elfcpp::Elf_Word type, + elfcpp::Elf_Xword flags, Output_section_order order, + bool is_relro); + + // Attach a section to a segment. + void + attach_section_to_segment(const Target*, Output_section*); + + // Get section order. + Output_section_order + default_section_order(Output_section*, bool is_relro_local); + + // Attach an allocated section to a segment. + void + attach_allocated_section_to_segment(const Target*, Output_section*); + + // Make the .eh_frame section. + Output_section* + make_eh_frame_section(const Relobj*); + + // Set the final file offsets of all the segments. + off_t + set_segment_offsets(const Target*, Output_segment*, unsigned int* pshndx); + + // Set the file offsets of the sections when doing a relocatable + // link. + off_t + set_relocatable_section_offsets(Output_data*, unsigned int* pshndx); + + // Set the final file offsets of all the sections not associated + // with a segment. We set section offsets in three passes: the + // first handles all allocated sections, the second sections that + // require postprocessing, and the last the late-bound STRTAB + // sections (probably only shstrtab, which is the one we care about + // because it holds section names). + enum Section_offset_pass + { + BEFORE_INPUT_SECTIONS_PASS, + POSTPROCESSING_SECTIONS_PASS, + STRTAB_AFTER_POSTPROCESSING_SECTIONS_PASS + }; + off_t + set_section_offsets(off_t, Section_offset_pass pass); + + // Set the final section indexes of all the sections not associated + // with a segment. Returns the next unused index. + unsigned int + set_section_indexes(unsigned int pshndx); + + // Set the section addresses when using a script. + Output_segment* + set_section_addresses_from_script(Symbol_table*); + + // Find appropriate places or orphan sections in a script. + void + place_orphan_sections_in_script(); + + // Return whether SEG1 comes before SEG2 in the output file. + bool + segment_precedes(const Output_segment* seg1, const Output_segment* seg2); + + // Use to save and restore segments during relaxation. + typedef Unordered_map + Segment_states; + + // Save states of current output segments. + void + save_segments(Segment_states*); + + // Restore output segment states. + void + restore_segments(const Segment_states*); + + // Clean up after relaxation so that it is possible to lay out the + // sections and segments again. + void + clean_up_after_relaxation(); + + // Doing preparation work for relaxation. This is factored out to make + // Layout::finalized a bit smaller and easier to read. + void + prepare_for_relaxation(); + + // Main body of the relaxation loop, which lays out the section. + off_t + relaxation_loop_body(int, Target*, Symbol_table*, Output_segment**, + Output_segment*, Output_segment_headers*, + Output_file_header*, unsigned int*); + + // A mapping used for kept comdats/.gnu.linkonce group signatures. + typedef Unordered_map Signatures; + + // Mapping from input section name/type/flags to output section. We + // use canonicalized strings here. + + typedef std::pair > Key; + + struct Hash_key + { + size_t + operator()(const Key& k) const; + }; + + typedef Unordered_map Section_name_map; + + // A comparison class for segments. + + class Compare_segments + { + public: + Compare_segments(Layout* layout) + : layout_(layout) + { } + + bool + operator()(const Output_segment* seg1, const Output_segment* seg2) + { return this->layout_->segment_precedes(seg1, seg2); } + + private: + Layout* layout_; + }; + + typedef std::vector Output_section_data_list; + + // Debug checker class. + class Relaxation_debug_check + { + public: + 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& special_outputs, + const Layout::Data_list& relax_outputs); + + // Record information of a section list. + void + read_sections(const Layout::Section_list&); + + // Verify a section list with recorded information. + void + verify_sections(const Layout::Section_list&); + + private: + // Information we care about a section. + struct Section_info + { + // Output section described by this. + Output_section* output_section; + // Load address. + uint64_t address; + // Data size. + off_t data_size; + // File offset. + off_t offset; + }; + + // Section information. + std::vector section_infos_; + }; + + // The number of input files, for sizing tables. + int number_of_input_files_; + // Information set by scripts or by command line options. + Script_options* script_options_; + // The output section names. + Stringpool namepool_; + // The output symbol names. + Stringpool sympool_; + // The dynamic strings, if needed. + Stringpool dynpool_; + // The list of group sections and linkonce sections which we have seen. + Signatures signatures_; + // The mapping from input section name/type/flags to output sections. + Section_name_map section_name_map_; + // The list of output segments. + Segment_list segment_list_; + // The list of output sections. + Section_list section_list_; + // The list of output sections which are not attached to any output + // segment. + Section_list unattached_section_list_; + // The list of unattached Output_data objects which require special + // handling because they are not Output_sections. + Data_list special_output_list_; + // Like special_output_list_, but cleared and recreated on each + // iteration of relaxation. + Data_list relax_output_list_; + // The section headers. + Output_section_headers* section_headers_; + // A pointer to the PT_TLS segment if there is one. + Output_segment* tls_segment_; + // A pointer to the PT_GNU_RELRO segment if there is one. + Output_segment* relro_segment_; + // A pointer to the PT_INTERP segment if there is one. + Output_segment* interp_segment_; + // A backend may increase the size of the PT_GNU_RELRO segment if + // there is one. This is the amount to increase it by. + unsigned int increase_relro_; + // The SHT_SYMTAB output section. + Output_section* symtab_section_; + // The SHT_SYMTAB_SHNDX for the regular symbol table if there is one. + Output_symtab_xindex* symtab_xindex_; + // The SHT_DYNSYM output section if there is one. + Output_section* dynsym_section_; + // The SHT_SYMTAB_SHNDX for the dynamic symbol table if there is one. + Output_symtab_xindex* dynsym_xindex_; + // The SHT_DYNAMIC output section if there is one. + Output_section* dynamic_section_; + // The _DYNAMIC symbol if there is one. + Symbol* dynamic_symbol_; + // The dynamic data which goes into dynamic_section_. + Output_data_dynamic* dynamic_data_; + // The exception frame output section if there is one. + Output_section* eh_frame_section_; + // The exception frame data for eh_frame_section_. + Eh_frame* eh_frame_data_; + // Whether we have added eh_frame_data_ to the .eh_frame section. + bool added_eh_frame_data_; + // The exception frame header output section if there is one. + Output_section* eh_frame_hdr_section_; + // The data for the .gdb_index section. + Gdb_index* gdb_index_data_; + // The space for the build ID checksum if there is one. + Output_section_data* build_id_note_; + // Temporary storage for tree hash of build ID. + unsigned char* array_of_hashes_; + // Size of array_of_hashes_ (in bytes). + size_t size_of_array_of_hashes_; + // Input view for computing tree hash of build ID. Freed in write_build_id(). + const unsigned char* input_view_; + // The output section containing dwarf abbreviations + Output_reduced_debug_abbrev_section* debug_abbrev_; + // The output section containing the dwarf debug info tree + Output_reduced_debug_info_section* debug_info_; + // A list of group sections and their signatures. + Group_signatures group_signatures_; + // The size of the output file. + off_t output_file_size_; + // Whether we have added an input section to an output section. + bool have_added_input_section_; + // Whether we have attached the sections to the segments. + bool sections_are_attached_; + // Whether we have seen an object file marked to require an + // executable stack. + bool input_requires_executable_stack_; + // Whether we have seen at least one object file with an executable + // stack marker. + bool input_with_gnu_stack_note_; + // Whether we have seen at least one object file without an + // executable stack marker. + bool input_without_gnu_stack_note_; + // Whether we have seen an object file that uses the static TLS model. + bool has_static_tls_; + // Whether any sections require postprocessing. + bool any_postprocessing_sections_; + // Whether we have resized the signatures_ hash table. + bool resized_signatures_; + // Whether we have created a .stab*str output section. + bool have_stabstr_section_; + // True if the input sections in the output sections should be sorted + // as specified in a section ordering file. + bool section_ordering_specified_; + // True if some input sections need to be mapped to a unique segment, + // after being mapped to a unique Output_section. + bool unique_segment_for_sections_specified_; + // In incremental build, holds information check the inputs and build the + // .gnu_incremental_inputs section. + Incremental_inputs* incremental_inputs_; + // Whether we record output section data created in script + bool record_output_section_data_from_script_; + // List of output data that needs to be removed at relaxation clean up. + Output_section_data_list script_output_section_data_list_; + // Structure to save segment states before entering the relaxation loop. + Segment_states* segment_states_; + // A relaxation debug checker. We only create one when in debugging mode. + Relaxation_debug_check* relaxation_debug_check_; + // Plugins specify section_ordering using this map. This is set in + // update_section_order in plugin.cc + std::map section_order_map_; + // This maps an input section to a unique segment. This is done by first + // placing such input sections in unique output sections and then mapping + // the output section to a unique segment. Unique_segment_info stores + // any additional flags and alignment of the new segment. + Section_segment_map section_segment_map_; + // Hash a pattern to its position in the section ordering file. + Unordered_map input_section_position_; + // Vector of glob only patterns in the section_ordering file. + std::vector input_section_glob_; + // For incremental links, the base file to be modified. + Incremental_binary* incremental_base_; + // For incremental links, a list of free space within the file. + Free_list free_list_; +}; + +// This task handles writing out data in output sections which is not +// part of an input section, or which requires special handling. When +// this is done, it unblocks both output_sections_blocker and +// final_blocker. + +class Write_sections_task : public Task +{ + public: + Write_sections_task(const Layout* layout, Output_file* of, + Task_token* output_sections_blocker, + Task_token* final_blocker) + : layout_(layout), of_(of), + output_sections_blocker_(output_sections_blocker), + final_blocker_(final_blocker) + { } + + // The standard Task methods. + + Task_token* + is_runnable(); + + void + locks(Task_locker*); + + void + run(Workqueue*); + + std::string + get_name() const + { return "Write_sections_task"; } + + private: + class Write_sections_locker; + + const Layout* layout_; + Output_file* of_; + Task_token* output_sections_blocker_; + Task_token* final_blocker_; +}; + +// This task handles writing out data which is not part of a section +// or segment. + +class Write_data_task : public Task +{ + public: + Write_data_task(const Layout* layout, const Symbol_table* symtab, + Output_file* of, Task_token* final_blocker) + : layout_(layout), symtab_(symtab), of_(of), final_blocker_(final_blocker) + { } + + // The standard Task methods. + + Task_token* + is_runnable(); + + void + locks(Task_locker*); + + void + run(Workqueue*); + + std::string + get_name() const + { return "Write_data_task"; } + + private: + const Layout* layout_; + const Symbol_table* symtab_; + Output_file* of_; + Task_token* final_blocker_; +}; + +// This task handles writing out the global symbols. + +class Write_symbols_task : public Task +{ + public: + Write_symbols_task(const Layout* layout, const Symbol_table* symtab, + const Input_objects* /*input_objects*/, + const Stringpool* sympool, const Stringpool* dynpool, + Output_file* of, Task_token* final_blocker) + : layout_(layout), symtab_(symtab), + sympool_(sympool), dynpool_(dynpool), of_(of), + final_blocker_(final_blocker) + { } + + // The standard Task methods. + + Task_token* + is_runnable(); + + void + locks(Task_locker*); + + void + run(Workqueue*); + + std::string + get_name() const + { return "Write_symbols_task"; } + + private: + const Layout* layout_; + const Symbol_table* symtab_; + const Stringpool* sympool_; + const Stringpool* dynpool_; + Output_file* of_; + Task_token* final_blocker_; +}; + +// This task handles writing out data in output sections which can't +// be written out until all the input sections have been handled. +// This is for sections whose contents is based on the contents of +// other output sections. + +class Write_after_input_sections_task : public Task +{ + public: + Write_after_input_sections_task(Layout* layout, Output_file* of, + Task_token* input_sections_blocker, + Task_token* final_blocker) + : layout_(layout), of_(of), + input_sections_blocker_(input_sections_blocker), + final_blocker_(final_blocker) + { } + + // The standard Task methods. + + Task_token* + is_runnable(); + + void + locks(Task_locker*); + + void + run(Workqueue*); + + std::string + get_name() const + { return "Write_after_input_sections_task"; } + + private: + Layout* layout_; + Output_file* of_; + Task_token* input_sections_blocker_; + Task_token* final_blocker_; +}; + +// This task function handles closing the file. + +class Close_task_runner : public Task_function_runner +{ + public: + Close_task_runner(const General_options* options, const Layout* layout, + Output_file* of) + : options_(options), layout_(layout), of_(of) + { } + + // Run the operation. + void + run(Workqueue*, const Task*); + + private: + const General_options* options_; + const Layout* layout_; + Output_file* of_; +}; + +// A small helper function to align an address. + +inline uint64_t +align_address(uint64_t address, uint64_t addralign) +{ + if (addralign != 0) + address = (address + addralign - 1) &~ (addralign - 1); + return address; +} + +} // End namespace gold. + +#endif // !defined(GOLD_LAYOUT_H) diff --git a/binutils-2.25/gold/main.cc b/binutils-2.25/gold/main.cc new file mode 100644 index 00000000..d3292981 --- /dev/null +++ b/binutils-2.25/gold/main.cc @@ -0,0 +1,332 @@ +// main.cc -- gold main function. + +// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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 +#include + +#ifdef HAVE_MALLINFO +#include +#endif + +#include "libiberty.h" + +#include "script.h" +#include "options.h" +#include "target-select.h" +#include "parameters.h" +#include "errors.h" +#include "mapfile.h" +#include "dirsearch.h" +#include "workqueue.h" +#include "object.h" +#include "archive.h" +#include "symtab.h" +#include "layout.h" +#include "plugin.h" +#include "gc.h" +#include "icf.h" +#include "incremental.h" +#include "gdb-index.h" +#include "timer.h" + +using namespace gold; + +// This function emits the commandline to a hard-coded file in temp. +// This is useful for debugging since ld is typically invoked by gcc, +// so its commandline is not always easy to extract. You should be +// able to run 'gcc -B... foo.o -o foo' to invoke this linker the +// first time, and then /tmp/ld-run-foo.sh to invoke it on subsequent +// runes. "/tmp/ld-run-foo.sh debug" will run the linker inside gdb +// (or whatever value the environment variable GDB is set to), for +// even easier debugging. Since this is a debugging-only tool, and +// creates files, it is only turned on when the user explicitly asks +// for it, by compiling with -DDEBUG. Do not do this for release +// versions of the linker! + +#ifdef DEBUG +#include +#include // for chmod() + +static std::string +collect_argv(int argc, char** argv) +{ + // This is used by write_debug_script(), which wants the unedited argv. + std::string args; + for (int i = 0; i < argc; ++i) + { + args.append(" '"); + // 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; + } + args.append("'"); + } + return args; +} + +static void +write_debug_script(std::string filename_str, + const char* argv_0, const char* args) +{ + size_t slash = filename_str.rfind('/'); + if (slash != std::string::npos) + filename_str = filename_str.c_str() + slash + 1; + filename_str = std::string("/tmp/ld-run-") + filename_str + ".sh"; + const char* filename = filename_str.c_str(); + FILE* fp = fopen(filename, "w"); + if (fp) + { + fprintf(fp, "[ \"$1\" = debug ]" + " && PREFIX=\"${GDB-gdb} --annotate=3 --fullname %s --args\"" + " && shift\n", + argv_0); + fprintf(fp, "$PREFIX%s $*\n", args); + fclose(fp); + chmod(filename, 0755); + } + else + filename = "[none]"; + fprintf(stderr, "Welcome to gold! Commandline written to %s.\n", filename); + fflush(stderr); +} + +#else // !defined(DEBUG) + +static inline std::string +collect_argv(int, char**) +{ + return ""; +} + +static inline void +write_debug_script(std::string, const char*, const char*) +{ +} + +#endif // !defined(DEBUG) + + +int +main(int argc, char** argv) +{ +#if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES) + setlocale(LC_MESSAGES, ""); +#endif +#if defined (HAVE_SETLOCALE) + setlocale(LC_CTYPE, ""); +#endif + bindtextdomain(PACKAGE, LOCALEDIR); + textdomain(PACKAGE); + + program_name = argv[0]; + + // In libiberty; expands @filename to the args in "filename". + expandargv(&argc, &argv); + + // This is used by write_debug_script(), which wants the unedited argv. + std::string args = collect_argv(argc, argv); + + Errors errors(program_name); + + // Initialize the global parameters, to let random code get to the + // errors object. + set_parameters_errors(&errors); + + // Handle the command line options. + Command_line command_line; + command_line.process(argc - 1, const_cast(argv + 1)); + + Timer timer; + if (command_line.options().stats()) + { + timer.start(); + set_parameters_timer(&timer); + } + + // Store some options in the globally accessible parameters. + set_parameters_options(&command_line.options()); + + // Do this as early as possible (since it prints a welcome message). + write_debug_script(command_line.options().output_file_name(), + program_name, args.c_str()); + + // If the user asked for a map file, open it. + Mapfile* mapfile = NULL; + if (command_line.options().user_set_Map()) + { + mapfile = new Mapfile(); + if (!mapfile->open(command_line.options().Map())) + { + delete mapfile; + mapfile = NULL; + } + } + + // The GNU linker ignores version scripts when generating + // relocatable output. If we are not compatible, then we break the + // Linux kernel build, which uses a linker script with -r which must + // not force symbols to be local. It would actually be useful to + // permit symbols to be forced local with -r, though, as it would + // permit some linker optimizations. Perhaps we need yet another + // option to control this. FIXME. + if (parameters->options().relocatable()) + command_line.script_options().version_script_info()->clear(); + + // The work queue. + Workqueue workqueue(command_line.options()); + + // The list of input objects. + Input_objects input_objects; + + // The Garbage Collection (GC, --gc-sections) Object. + Garbage_collection gc; + + // The Identical Code Folding (ICF, --icf) Object. + Icf icf; + + // The symbol table. We're going to guess here how many symbols + // we're going to see based on the number of input files. Even when + // this is off, it means at worst we don't quite optimize hashtable + // resizing as well as we could have (perhaps using more memory). + Symbol_table symtab(command_line.number_of_input_files() * 1024, + command_line.version_script()); + + if (parameters->options().gc_sections()) + symtab.set_gc(&gc); + + if (parameters->options().icf_enabled()) + symtab.set_icf(&icf); + + // The layout object. + Layout layout(command_line.number_of_input_files(), + &command_line.script_options()); + + if (layout.incremental_inputs() != NULL) + layout.incremental_inputs()->report_command_line(argc, argv); + + if (parameters->options().section_ordering_file()) + layout.read_layout_from_file(); + + // Load plugin libraries. + if (command_line.options().has_plugins()) + command_line.options().plugins()->load_plugins(&layout); + + // Get the search path from the -L options. + Dirsearch search_path; + search_path.initialize(&workqueue, &command_line.options().library_path()); + + // Queue up the first set of tasks. + queue_initial_tasks(command_line.options(), search_path, + command_line, &workqueue, &input_objects, + &symtab, &layout, mapfile); + + // Run the main task processing loop. + workqueue.process(0); + + if (command_line.options().print_output_format()) + print_output_format(); + + if (command_line.options().stats()) + { + timer.stamp(2); + Timer::TimeStats elapsed = timer.get_pass_time(0); + fprintf(stderr, + _("%s: initial tasks run time: " \ + "(user: %ld.%06ld sys: %ld.%06ld wall: %ld.%06ld)\n"), + program_name, + elapsed.user / 1000, (elapsed.user % 1000) * 1000, + elapsed.sys / 1000, (elapsed.sys % 1000) * 1000, + elapsed.wall / 1000, (elapsed.wall % 1000) * 1000); + elapsed = timer.get_pass_time(1); + fprintf(stderr, + _("%s: middle tasks run time: " \ + "(user: %ld.%06ld sys: %ld.%06ld wall: %ld.%06ld)\n"), + program_name, + elapsed.user / 1000, (elapsed.user % 1000) * 1000, + elapsed.sys / 1000, (elapsed.sys % 1000) * 1000, + elapsed.wall / 1000, (elapsed.wall % 1000) * 1000); + elapsed = timer.get_pass_time(2); + fprintf(stderr, + _("%s: final tasks run time: " \ + "(user: %ld.%06ld sys: %ld.%06ld wall: %ld.%06ld)\n"), + program_name, + elapsed.user / 1000, (elapsed.user % 1000) * 1000, + elapsed.sys / 1000, (elapsed.sys % 1000) * 1000, + elapsed.wall / 1000, (elapsed.wall % 1000) * 1000); + elapsed = timer.get_elapsed_time(); + fprintf(stderr, + _("%s: total run time: " \ + "(user: %ld.%06ld sys: %ld.%06ld wall: %ld.%06ld)\n"), + program_name, + elapsed.user / 1000, (elapsed.user % 1000) * 1000, + elapsed.sys / 1000, (elapsed.sys % 1000) * 1000, + elapsed.wall / 1000, (elapsed.wall % 1000) * 1000); + +#ifdef HAVE_MALLINFO + struct mallinfo m = mallinfo(); + fprintf(stderr, _("%s: total space allocated by malloc: %d bytes\n"), + program_name, m.arena); +#endif + File_read::print_stats(); + Archive::print_stats(); + Lib_group::print_stats(); + fprintf(stderr, _("%s: output file size: %lld bytes\n"), + program_name, static_cast(layout.output_file_size())); + symtab.print_stats(); + layout.print_stats(); + Gdb_index::print_stats(); + Free_list::print_stats(); + } + + // Issue defined symbol report. + if (command_line.options().user_set_print_symbol_counts()) + input_objects.print_symbol_counts(&symtab); + + // Output cross reference table. + if (command_line.options().cref()) + input_objects.print_cref(&symtab, + mapfile == NULL ? stdout : mapfile->file()); + + if (mapfile != NULL) + mapfile->close(); + + if (parameters->options().fatal_warnings() + && errors.warning_count() > 0 + && errors.error_count() == 0) + gold_error("treating warnings as errors"); + + // If the user used --noinhibit-exec, we force the exit status to be + // successful. This is compatible with GNU ld. + gold_exit((errors.error_count() == 0 + || parameters->options().noinhibit_exec()) + ? GOLD_OK + : GOLD_ERR); +} diff --git a/binutils-2.25/gold/mapfile.cc b/binutils-2.25/gold/mapfile.cc new file mode 100644 index 00000000..2062ae40 --- /dev/null +++ b/binutils-2.25/gold/mapfile.cc @@ -0,0 +1,404 @@ +// mapfile.cc -- map file generation for gold + +// Copyright 2008 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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 +#include +#include + +#include "archive.h" +#include "symtab.h" +#include "output.h" +#include "mapfile.h" + +// This file holds the code for printing information to the map file. +// In general we try to produce pretty much the same format as GNU ld. + +namespace gold +{ + +// Mapfile constructor. + +Mapfile::Mapfile() + : map_file_(NULL), + printed_archive_header_(false), + printed_common_header_(false), + printed_memory_map_header_(false) +{ +} + +// Mapfile destructor. + +Mapfile::~Mapfile() +{ + if (this->map_file_ != NULL) + this->close(); +} + +// Open the map file. + +bool +Mapfile::open(const char* map_filename) +{ + if (strcmp(map_filename, "-") == 0) + this->map_file_ = stdout; + else + { + this->map_file_ = ::fopen(map_filename, "w"); + if (this->map_file_ == NULL) + { + gold_error(_("cannot open map file %s: %s"), map_filename, + strerror(errno)); + return false; + } + } + return true; +} + +// Close the map file. + +void +Mapfile::close() +{ + if (fclose(this->map_file_) != 0) + gold_error(_("cannot close map file: %s"), strerror(errno)); + this->map_file_ = NULL; +} + +// Advance to a column. + +void +Mapfile::advance_to_column(size_t from, size_t to) +{ + if (from >= to - 1) + { + putc('\n', this->map_file_); + from = 0; + } + while (from < to) + { + putc(' ', this->map_file_); + ++from; + } +} + +// Report about including a member from an archive. + +void +Mapfile::report_include_archive_member(const std::string& member_name, + const Symbol* sym, const char* why) +{ + // We print a header before the list of archive members, mainly for + // GNU ld compatibility. + if (!this->printed_archive_header_) + { + fprintf(this->map_file_, + _("Archive member included because of file (symbol)\n\n")); + this->printed_archive_header_ = true; + } + + fprintf(this->map_file_, "%s", member_name.c_str()); + + this->advance_to_column(member_name.length(), 30); + + if (sym == NULL) + fprintf(this->map_file_, "%s", why); + else + { + switch (sym->source()) + { + case Symbol::FROM_OBJECT: + fprintf(this->map_file_, "%s", sym->object()->name().c_str()); + break; + + case Symbol::IS_UNDEFINED: + fprintf(this->map_file_, "-u"); + break; + + default: + case Symbol::IN_OUTPUT_DATA: + case Symbol::IN_OUTPUT_SEGMENT: + case Symbol::IS_CONSTANT: + // We should only see an undefined symbol here. + gold_unreachable(); + } + + fprintf(this->map_file_, " (%s)", sym->name()); + } + + putc('\n', this->map_file_); +} + +// Report allocating a common symbol. + +void +Mapfile::report_allocate_common(const Symbol* sym, uint64_t symsize) +{ + if (!this->printed_common_header_) + { + fprintf(this->map_file_, _("\nAllocating common symbols\n")); + fprintf(this->map_file_, + _("Common symbol size file\n\n")); + this->printed_common_header_ = true; + } + + std::string demangled_name = sym->demangled_name(); + fprintf(this->map_file_, "%s", demangled_name.c_str()); + + this->advance_to_column(demangled_name.length(), 20); + + char buf[50]; + snprintf(buf, sizeof buf, "0x%llx", static_cast(symsize)); + fprintf(this->map_file_, "%s", buf); + + size_t len = strlen(buf); + while (len < 18) + { + putc(' ', this->map_file_); + ++len; + } + + fprintf(this->map_file_, "%s\n", sym->object()->name().c_str()); +} + +// The space we make for a section name. + +const size_t Mapfile::section_name_map_length = 16; + +// Print the memory map header if necessary. + +void +Mapfile::print_memory_map_header() +{ + if (!this->printed_memory_map_header_) + { + fprintf(this->map_file_, _("\nMemory map\n\n")); + this->printed_memory_map_header_ = true; + } +} + +// Print the symbols associated with an input section. + +template +void +Mapfile::print_input_section_symbols( + const Sized_relobj_file* relobj, + unsigned int shndx) +{ + unsigned int symcount = relobj->symbol_count(); + for (unsigned int i = relobj->local_symbol_count(); i < symcount; ++i) + { + const Symbol* sym = relobj->global_symbol(i); + bool is_ordinary; + if (sym != NULL + && sym->source() == Symbol::FROM_OBJECT + && sym->object() == relobj + && sym->shndx(&is_ordinary) == shndx + && is_ordinary + && sym->is_defined()) + { + for (size_t i = 0; i < Mapfile::section_name_map_length; ++i) + putc(' ', this->map_file_); + const Sized_symbol* ssym = + static_cast*>(sym); + fprintf(this->map_file_, + "0x%0*llx %s\n", + size / 4, + static_cast(ssym->value()), + sym->demangled_name().c_str()); + } + } +} + +// Print an input section. + +void +Mapfile::print_input_section(Relobj* relobj, unsigned int shndx) +{ + putc(' ', this->map_file_); + + std::string name = relobj->section_name(shndx); + fprintf(this->map_file_, "%s", name.c_str()); + + this->advance_to_column(name.length() + 1, Mapfile::section_name_map_length); + + Output_section* os; + uint64_t addr; + if (!relobj->is_section_included(shndx)) + { + os = NULL; + addr = 0; + } + else + { + os = relobj->output_section(shndx); + addr = relobj->output_section_offset(shndx); + if (addr != -1ULL) + addr += os->address(); + } + + char sizebuf[50]; + snprintf(sizebuf, sizeof sizebuf, "0x%llx", + static_cast(relobj->section_size(shndx))); + + fprintf(this->map_file_, "0x%0*llx %10s %s\n", + parameters->target().get_size() / 4, + static_cast(addr), sizebuf, + relobj->name().c_str()); + + if (os != NULL) + { + switch (parameters->size_and_endianness()) + { +#ifdef HAVE_TARGET_32_LITTLE + case Parameters::TARGET_32_LITTLE: + { + const Sized_relobj_file<32, false>* sized_relobj = + static_cast*>(relobj); + this->print_input_section_symbols(sized_relobj, shndx); + } + break; +#endif +#ifdef HAVE_TARGET_32_BIG + case Parameters::TARGET_32_BIG: + { + const Sized_relobj_file<32, true>* sized_relobj = + static_cast*>(relobj); + this->print_input_section_symbols(sized_relobj, shndx); + } + break; +#endif +#ifdef HAVE_TARGET_64_LITTLE + case Parameters::TARGET_64_LITTLE: + { + const Sized_relobj_file<64, false>* sized_relobj = + static_cast*>(relobj); + this->print_input_section_symbols(sized_relobj, shndx); + } + break; +#endif +#ifdef HAVE_TARGET_64_BIG + case Parameters::TARGET_64_BIG: + { + const Sized_relobj_file<64, true>* sized_relobj = + static_cast*>(relobj); + this->print_input_section_symbols(sized_relobj, shndx); + } + break; +#endif + default: + gold_unreachable(); + } + } +} + +// Print an Output_section_data. This is printed to look like an +// input section. + +void +Mapfile::print_output_data(const Output_data* od, const char* name) +{ + this->print_memory_map_header(); + + putc(' ', this->map_file_); + + fprintf(this->map_file_, "%s", name); + + this->advance_to_column(strlen(name) + 1, Mapfile::section_name_map_length); + + char sizebuf[50]; + snprintf(sizebuf, sizeof sizebuf, "0x%llx", + static_cast(od->data_size())); + + fprintf(this->map_file_, "0x%0*llx %10s\n", + parameters->target().get_size() / 4, + static_cast(od->address()), + sizebuf); +} + +// Print the discarded input sections. + +void +Mapfile::print_discarded_sections(const Input_objects* input_objects) +{ + bool printed_header = false; + for (Input_objects::Relobj_iterator p = input_objects->relobj_begin(); + p != input_objects->relobj_end(); + ++p) + { + Relobj* relobj = *p; + // Lock the object so we can read from it. This is only called + // single-threaded from Layout_task_runner, so it is OK to lock. + // Unfortunately we have no way to pass in a Task token. + const Task* dummy_task = reinterpret_cast(-1); + Task_lock_obj tl(dummy_task, relobj); + + unsigned int shnum = relobj->shnum(); + for (unsigned int i = 0; i < shnum; ++i) + { + unsigned int sh_type = relobj->section_type(i); + if ((sh_type == elfcpp::SHT_PROGBITS + || sh_type == elfcpp::SHT_NOBITS + || sh_type == elfcpp::SHT_GROUP) + && !relobj->is_section_included(i)) + { + if (!printed_header) + { + fprintf(this->map_file_, _("\nDiscarded input sections\n\n")); + printed_header = true; + } + + this->print_input_section(relobj, i); + } + } + } +} + +// Print an output section. + +void +Mapfile::print_output_section(const Output_section* os) +{ + this->print_memory_map_header(); + + fprintf(this->map_file_, "\n%s", os->name()); + + this->advance_to_column(strlen(os->name()), Mapfile::section_name_map_length); + + char sizebuf[50]; + snprintf(sizebuf, sizeof sizebuf, "0x%llx", + static_cast(os->data_size())); + + fprintf(this->map_file_, "0x%0*llx %10s", + parameters->target().get_size() / 4, + static_cast(os->address()), sizebuf); + + if (os->has_load_address()) + fprintf(this->map_file_, " load address 0x%-*llx", + parameters->target().get_size() / 4, + static_cast(os->load_address())); + + putc('\n', this->map_file_); +} + +} // End namespace gold. diff --git a/binutils-2.25/gold/mapfile.h b/binutils-2.25/gold/mapfile.h new file mode 100644 index 00000000..808fc665 --- /dev/null +++ b/binutils-2.25/gold/mapfile.h @@ -0,0 +1,118 @@ +// mapfile.h -- map file generation for gold -*- C++ -*- + +// Copyright 2008, 2010 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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. + +#ifndef GOLD_MAP_H +#define GOLD_MAP_H + +#include +#include + +namespace gold +{ + +class Archive; +class Symbol; +class Relobj; +template +class Sized_relobj_file; +class Output_section; +class Output_data; + +// This class manages map file output. + +class Mapfile +{ + public: + Mapfile(); + + ~Mapfile(); + + // Open the map file. Return whether the open succeed. + bool + open(const char* map_filename); + + // Close the map file. + void + close(); + + // Return the underlying file. + FILE* + file() + { return this->map_file_; } + + // Report that we are including a member from an archive. This is + // called by the archive reading code. + void + report_include_archive_member(const std::string& member_name, + const Symbol* sym, const char* why); + + // Report allocating a common symbol. + void + report_allocate_common(const Symbol*, uint64_t symsize); + + // Print discarded input sections. + void + print_discarded_sections(const Input_objects*); + + // Print an output section. + void + print_output_section(const Output_section*); + + // Print an input section. + void + print_input_section(Relobj*, unsigned int shndx); + + // Print an Output_data. + void + print_output_data(const Output_data*, const char* name); + + private: + // The space we allow for a section name. + static const size_t section_name_map_length; + + // Advance to a column. + void + advance_to_column(size_t from, size_t to); + + // Print the memory map header. + void + print_memory_map_header(); + + // Print symbols for an input section. + template + void + print_input_section_symbols(const Sized_relobj_file*, + unsigned int shndx); + + // Map file to write to. + FILE* map_file_; + // Whether we have printed the archive member header. + bool printed_archive_header_; + // Whether we have printed the allocated common header. + bool printed_common_header_; + // Whether we have printed the memory map header. + bool printed_memory_map_header_; +}; + +} // End namespace gold. + +#endif // !defined(GOLD_MAP_H) diff --git a/binutils-2.25/gold/merge.cc b/binutils-2.25/gold/merge.cc new file mode 100644 index 00000000..f370c9cb --- /dev/null +++ b/binutils-2.25/gold/merge.cc @@ -0,0 +1,762 @@ +// merge.cc -- handle section merging for gold + +// Copyright 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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 +#include + +#include "merge.h" +#include "compressed_output.h" + +namespace gold +{ + +// Class Object_merge_map. + +// Destructor. + +Object_merge_map::~Object_merge_map() +{ + for (Section_merge_maps::iterator p = this->section_merge_maps_.begin(); + p != this->section_merge_maps_.end(); + ++p) + delete p->second; +} + +// Get the Input_merge_map to use for an input section, or NULL. + +Object_merge_map::Input_merge_map* +Object_merge_map::get_input_merge_map(unsigned int shndx) +{ + gold_assert(shndx != -1U); + if (shndx == this->first_shnum_) + return &this->first_map_; + if (shndx == this->second_shnum_) + return &this->second_map_; + Section_merge_maps::const_iterator p = this->section_merge_maps_.find(shndx); + if (p != this->section_merge_maps_.end()) + return p->second; + return NULL; +} + +// Get or create the Input_merge_map to use for an input section. + +Object_merge_map::Input_merge_map* +Object_merge_map::get_or_make_input_merge_map(const Merge_map* merge_map, + unsigned int shndx) +{ + Input_merge_map* map = this->get_input_merge_map(shndx); + if (map != NULL) + { + // For a given input section in a given object, every mapping + // must be done with the same Merge_map. + gold_assert(map->merge_map == merge_map); + return map; + } + + // We need to create a new entry. + if (this->first_shnum_ == -1U) + { + this->first_shnum_ = shndx; + this->first_map_.merge_map = merge_map; + return &this->first_map_; + } + if (this->second_shnum_ == -1U) + { + this->second_shnum_ = shndx; + this->second_map_.merge_map = merge_map; + return &this->second_map_; + } + + Input_merge_map* new_map = new Input_merge_map; + new_map->merge_map = merge_map; + this->section_merge_maps_[shndx] = new_map; + return new_map; +} + +// Add a mapping. + +void +Object_merge_map::add_mapping(const Merge_map* merge_map, unsigned int shndx, + section_offset_type input_offset, + section_size_type length, + section_offset_type output_offset) +{ + Input_merge_map* map = this->get_or_make_input_merge_map(merge_map, shndx); + + // Try to merge the new entry in the last one we saw. + if (!map->entries.empty()) + { + Input_merge_entry& entry(map->entries.back()); + + // Use section_size_type to avoid signed/unsigned warnings. + section_size_type input_offset_u = input_offset; + section_size_type output_offset_u = output_offset; + + // If this entry is not in order, we need to sort the vector + // before looking anything up. + if (input_offset_u < entry.input_offset + entry.length) + { + gold_assert(input_offset < entry.input_offset); + gold_assert(input_offset_u + length + <= static_cast(entry.input_offset)); + map->sorted = false; + } + else if (entry.input_offset + entry.length == input_offset_u + && (output_offset == -1 + ? entry.output_offset == -1 + : entry.output_offset + entry.length == output_offset_u)) + { + entry.length += length; + return; + } + } + + Input_merge_entry entry; + entry.input_offset = input_offset; + entry.length = length; + entry.output_offset = output_offset; + map->entries.push_back(entry); +} + +// Get the output offset for an input address. + +bool +Object_merge_map::get_output_offset(const Merge_map* merge_map, + unsigned int shndx, + section_offset_type input_offset, + section_offset_type* output_offset) +{ + Input_merge_map* map = this->get_input_merge_map(shndx); + if (map == NULL + || (merge_map != NULL && map->merge_map != merge_map)) + return false; + + if (!map->sorted) + { + std::sort(map->entries.begin(), map->entries.end(), + Input_merge_compare()); + map->sorted = true; + } + + Input_merge_entry entry; + entry.input_offset = input_offset; + std::vector::const_iterator p = + std::lower_bound(map->entries.begin(), map->entries.end(), + entry, Input_merge_compare()); + if (p == map->entries.end() || p->input_offset > input_offset) + { + if (p == map->entries.begin()) + return false; + --p; + gold_assert(p->input_offset <= input_offset); + } + + if (input_offset - p->input_offset + >= static_cast(p->length)) + return false; + + *output_offset = p->output_offset; + if (*output_offset != -1) + *output_offset += (input_offset - p->input_offset); + return true; +} + +// Return whether this is the merge map for section SHNDX. + +inline bool +Object_merge_map::is_merge_section_for(const Merge_map* merge_map, + unsigned int shndx) +{ + Input_merge_map* map = this->get_input_merge_map(shndx); + return map != NULL && map->merge_map == merge_map; +} + +// Initialize a mapping from input offsets to output addresses. + +template +void +Object_merge_map::initialize_input_to_output_map( + unsigned int shndx, + typename elfcpp::Elf_types::Elf_Addr starting_address, + Unordered_map::Elf_Addr>* initialize_map) +{ + Input_merge_map* map = this->get_input_merge_map(shndx); + gold_assert(map != NULL); + + gold_assert(initialize_map->empty()); + // We know how many entries we are going to add. + // reserve_unordered_map takes an expected count of buckets, not a + // count of elements, so double it to try to reduce collisions. + reserve_unordered_map(initialize_map, map->entries.size() * 2); + + for (Input_merge_map::Entries::const_iterator p = map->entries.begin(); + p != map->entries.end(); + ++p) + { + section_offset_type output_offset = p->output_offset; + if (output_offset != -1) + output_offset += starting_address; + else + { + // If we see a relocation against an address we have chosen + // to discard, we relocate to zero. FIXME: We could also + // issue a warning in this case; that would require + // reporting this somehow and checking it in the routines in + // reloc.h. + output_offset = 0; + } + initialize_map->insert(std::make_pair(p->input_offset, output_offset)); + } +} + +// Class Merge_map. + +// Add a mapping for the bytes from OFFSET to OFFSET + LENGTH in input +// section SHNDX in object OBJECT to an OUTPUT_OFFSET in merged data +// in an output section. + +void +Merge_map::add_mapping(Relobj* object, unsigned int shndx, + section_offset_type offset, section_size_type length, + section_offset_type output_offset) +{ + gold_assert(object != NULL); + Object_merge_map* object_merge_map = object->merge_map(); + if (object_merge_map == NULL) + { + object_merge_map = new Object_merge_map(); + object->set_merge_map(object_merge_map); + } + + object_merge_map->add_mapping(this, shndx, offset, length, output_offset); +} + +// Return the output offset for an input address. The input address +// is at offset OFFSET in section SHNDX in OBJECT. This sets +// *OUTPUT_OFFSET to the offset in the merged data in the output +// section. This returns true if the mapping is known, false +// otherwise. + +bool +Merge_map::get_output_offset(const Relobj* object, unsigned int shndx, + section_offset_type offset, + section_offset_type* output_offset) const +{ + Object_merge_map* object_merge_map = object->merge_map(); + if (object_merge_map == NULL) + return false; + return object_merge_map->get_output_offset(this, shndx, offset, + output_offset); +} + +// Return whether this is the merge section for SHNDX in OBJECT. + +bool +Merge_map::is_merge_section_for(const Relobj* object, unsigned int shndx) const +{ + Object_merge_map* object_merge_map = object->merge_map(); + if (object_merge_map == NULL) + return false; + return object_merge_map->is_merge_section_for(this, shndx); +} + +// Class Output_merge_base. + +// Return the output offset for an input offset. The input address is +// at offset OFFSET in section SHNDX in OBJECT. If we know the +// offset, set *POUTPUT and return true. Otherwise return false. + +bool +Output_merge_base::do_output_offset(const Relobj* object, + unsigned int shndx, + section_offset_type offset, + section_offset_type* poutput) const +{ + return this->merge_map_.get_output_offset(object, shndx, offset, poutput); +} + +// Return whether this is the merge section for SHNDX in OBJECT. + +bool +Output_merge_base::do_is_merge_section_for(const Relobj* object, + unsigned int shndx) const +{ + return this->merge_map_.is_merge_section_for(object, shndx); +} + +// Record a merged input section for script processing. + +void +Output_merge_base::record_input_section(Relobj* relobj, unsigned int shndx) +{ + gold_assert(this->keeps_input_sections_ && relobj != NULL); + // If this is the first input section, record it. We need do this because + // this->input_sections_ is unordered. + if (this->first_relobj_ == NULL) + { + this->first_relobj_ = relobj; + this->first_shndx_ = shndx; + } + + std::pair result = + this->input_sections_.insert(Section_id(relobj, shndx)); + // We should insert a merge section once only. + gold_assert(result.second); +} + +// Class Output_merge_data. + +// Compute the hash code for a fixed-size constant. + +size_t +Output_merge_data::Merge_data_hash::operator()(Merge_data_key k) const +{ + const unsigned char* p = this->pomd_->constant(k); + section_size_type entsize = + convert_to_section_size_type(this->pomd_->entsize()); + + // Fowler/Noll/Vo (FNV) hash (type FNV-1a). + if (sizeof(size_t) == 8) + { + size_t result = static_cast(14695981039346656037ULL); + for (section_size_type i = 0; i < entsize; ++i) + { + result &= (size_t) *p++; + result *= 1099511628211ULL; + } + return result; + } + else + { + size_t result = 2166136261UL; + for (section_size_type i = 0; i < entsize; ++i) + { + result ^= (size_t) *p++; + result *= 16777619UL; + } + return result; + } +} + +// Return whether one hash table key equals another. + +bool +Output_merge_data::Merge_data_eq::operator()(Merge_data_key k1, + Merge_data_key k2) const +{ + const unsigned char* p1 = this->pomd_->constant(k1); + const unsigned char* p2 = this->pomd_->constant(k2); + return memcmp(p1, p2, this->pomd_->entsize()) == 0; +} + +// Add a constant to the end of the section contents. + +void +Output_merge_data::add_constant(const unsigned char* p) +{ + section_size_type entsize = convert_to_section_size_type(this->entsize()); + section_size_type addralign = + convert_to_section_size_type(this->addralign()); + section_size_type addsize = std::max(entsize, addralign); + if (this->len_ + addsize > this->alc_) + { + if (this->alc_ == 0) + this->alc_ = 128 * addsize; + else + this->alc_ *= 2; + this->p_ = static_cast(realloc(this->p_, this->alc_)); + if (this->p_ == NULL) + gold_nomem(); + } + + memcpy(this->p_ + this->len_, p, entsize); + if (addsize > entsize) + memset(this->p_ + this->len_ + entsize, 0, addsize - entsize); + this->len_ += addsize; +} + +// Add the input section SHNDX in OBJECT to a merged output section +// which holds fixed length constants. Return whether we were able to +// handle the section; if not, it will be linked as usual without +// constant merging. + +bool +Output_merge_data::do_add_input_section(Relobj* object, unsigned int shndx) +{ + section_size_type len; + bool is_new; + const unsigned char* p = object->decompressed_section_contents(shndx, &len, + &is_new); + + section_size_type entsize = convert_to_section_size_type(this->entsize()); + + if (len % entsize != 0) + { + if (is_new) + delete[] p; + return false; + } + + this->input_count_ += len / entsize; + + for (section_size_type i = 0; i < len; i += entsize, p += entsize) + { + // Add the constant to the section contents. If we find that it + // is already in the hash table, we will remove it again. + Merge_data_key k = this->len_; + this->add_constant(p); + + std::pair ins = + this->hashtable_.insert(k); + + if (!ins.second) + { + // Key was already present. Remove the copy we just added. + this->len_ -= entsize; + k = *ins.first; + } + + // Record the offset of this constant in the output section. + this->add_mapping(object, shndx, i, entsize, k); + } + + // For script processing, we keep the input sections. + if (this->keeps_input_sections()) + record_input_section(object, shndx); + + if (is_new) + delete[] p; + + return true; +} + +// Set the final data size in a merged output section with fixed size +// constants. + +void +Output_merge_data::set_final_data_size() +{ + // Release the memory we don't need. + this->p_ = static_cast(realloc(this->p_, this->len_)); + // An Output_merge_data object may be empty and realloc is allowed + // to return a NULL pointer in this case. An Output_merge_data is empty + // if all its input sections have sizes that are not multiples of entsize. + gold_assert(this->p_ != NULL || this->len_ == 0); + this->set_data_size(this->len_); +} + +// Write the data of a merged output section with fixed size constants +// to the file. + +void +Output_merge_data::do_write(Output_file* of) +{ + of->write(this->offset(), this->p_, this->len_); +} + +// Write the data to a buffer. + +void +Output_merge_data::do_write_to_buffer(unsigned char* buffer) +{ + memcpy(buffer, this->p_, this->len_); +} + +// Print merge stats to stderr. + +void +Output_merge_data::do_print_merge_stats(const char* section_name) +{ + fprintf(stderr, + _("%s: %s merged constants size: %lu; input: %zu; output: %zu\n"), + program_name, section_name, + static_cast(this->entsize()), + this->input_count_, this->hashtable_.size()); +} + +// Class Output_merge_string. + +// Add an input section to a merged string section. + +template +bool +Output_merge_string::do_add_input_section(Relobj* object, + unsigned int shndx) +{ + section_size_type sec_len; + bool is_new; + const unsigned char* pdata = object->decompressed_section_contents(shndx, + &sec_len, + &is_new); + + const Char_type* p = reinterpret_cast(pdata); + const Char_type* pend = p + sec_len / sizeof(Char_type); + const Char_type* pend0 = pend; + + if (sec_len % sizeof(Char_type) != 0) + { + object->error(_("mergeable string section length not multiple of " + "character size")); + if (is_new) + delete[] pdata; + return false; + } + + if (pend[-1] != 0) + { + gold_warning(_("%s: last entry in mergeable string section '%s' " + "not null terminated"), + object->name().c_str(), + object->section_name(shndx).c_str()); + // Find the end of the last NULL-terminated string in the buffer. + while (pend0 > p && pend0[-1] != 0) + --pend0; + } + + Merged_strings_list* merged_strings_list = + new Merged_strings_list(object, shndx); + this->merged_strings_lists_.push_back(merged_strings_list); + Merged_strings& merged_strings = merged_strings_list->merged_strings; + + // Count the number of non-null strings in the section and size the list. + size_t count = 0; + const Char_type* pt = p; + while (pt < pend0) + { + size_t len = string_length(pt); + if (len != 0) + ++count; + pt += len + 1; + } + if (pend0 < pend) + ++count; + merged_strings.reserve(count + 1); + + // The index I is in bytes, not characters. + section_size_type i = 0; + + // We assume here that the beginning of the section is correctly + // aligned, so each string within the section must retain the same + // modulo. + uintptr_t init_align_modulo = (reinterpret_cast(pdata) + & (this->addralign() - 1)); + bool has_misaligned_strings = false; + + while (p < pend0) + { + size_t len = string_length(p); + + // Within merge input section each string must be aligned. + if (len != 0 + && ((reinterpret_cast(p) & (this->addralign() - 1)) + != init_align_modulo)) + has_misaligned_strings = true; + + Stringpool::Key key; + this->stringpool_.add_with_length(p, len, true, &key); + + merged_strings.push_back(Merged_string(i, key)); + p += len + 1; + i += (len + 1) * sizeof(Char_type); + } + if (p < pend) + { + size_t len = pend - p; + + Stringpool::Key key; + this->stringpool_.add_with_length(p, len, true, &key); + + merged_strings.push_back(Merged_string(i, key)); + + i += (len + 1) * sizeof(Char_type); + } + + // Record the last offset in the input section so that we can + // compute the length of the last string. + merged_strings.push_back(Merged_string(i, 0)); + + this->input_count_ += count; + this->input_size_ += i; + + if (has_misaligned_strings) + gold_warning(_("%s: section %s contains incorrectly aligned strings;" + " the alignment of those strings won't be preserved"), + object->name().c_str(), + object->section_name(shndx).c_str()); + + // For script processing, we keep the input sections. + if (this->keeps_input_sections()) + record_input_section(object, shndx); + + if (is_new) + delete[] pdata; + + return true; +} + +// Finalize the mappings from the input sections to the output +// section, and return the final data size. + +template +section_size_type +Output_merge_string::finalize_merged_data() +{ + this->stringpool_.set_string_offsets(); + + for (typename Merged_strings_lists::const_iterator l = + this->merged_strings_lists_.begin(); + l != this->merged_strings_lists_.end(); + ++l) + { + section_offset_type last_input_offset = 0; + section_offset_type last_output_offset = 0; + for (typename Merged_strings::const_iterator p = + (*l)->merged_strings.begin(); + p != (*l)->merged_strings.end(); + ++p) + { + section_size_type length = p->offset - last_input_offset; + if (length > 0) + this->add_mapping((*l)->object, (*l)->shndx, last_input_offset, + length, last_output_offset); + last_input_offset = p->offset; + if (p->stringpool_key != 0) + last_output_offset = + this->stringpool_.get_offset_from_key(p->stringpool_key); + } + delete *l; + } + + // Save some memory. This also ensures that this function will work + // if called twice, as may happen if Layout::set_segment_offsets + // finds a better alignment. + this->merged_strings_lists_.clear(); + + return this->stringpool_.get_strtab_size(); +} + +template +void +Output_merge_string::set_final_data_size() +{ + const off_t final_data_size = this->finalize_merged_data(); + this->set_data_size(final_data_size); +} + +// Write out a merged string section. + +template +void +Output_merge_string::do_write(Output_file* of) +{ + this->stringpool_.write(of, this->offset()); +} + +// Write a merged string section to a buffer. + +template +void +Output_merge_string::do_write_to_buffer(unsigned char* buffer) +{ + this->stringpool_.write_to_buffer(buffer, this->data_size()); +} + +// Return the name of the types of string to use with +// do_print_merge_stats. + +template +const char* +Output_merge_string::string_name() +{ + gold_unreachable(); + return NULL; +} + +template<> +const char* +Output_merge_string::string_name() +{ + return "strings"; +} + +template<> +const char* +Output_merge_string::string_name() +{ + return "16-bit strings"; +} + +template<> +const char* +Output_merge_string::string_name() +{ + return "32-bit strings"; +} + +// Print merge stats to stderr. + +template +void +Output_merge_string::do_print_merge_stats(const char* section_name) +{ + char buf[200]; + snprintf(buf, sizeof buf, "%s merged %s", section_name, this->string_name()); + fprintf(stderr, _("%s: %s input bytes: %zu\n"), + program_name, buf, this->input_size_); + fprintf(stderr, _("%s: %s input strings: %zu\n"), + program_name, buf, this->input_count_); + this->stringpool_.print_stats(buf); +} + +// Instantiate the templates we need. + +template +class Output_merge_string; + +template +class Output_merge_string; + +template +class Output_merge_string; + +#if defined(HAVE_TARGET_32_LITTLE) || defined(HAVE_TARGET_32_BIG) +template +void +Object_merge_map::initialize_input_to_output_map<32>( + unsigned int shndx, + elfcpp::Elf_types<32>::Elf_Addr starting_address, + Unordered_map::Elf_Addr>*); +#endif + +#if defined(HAVE_TARGET_64_LITTLE) || defined(HAVE_TARGET_64_BIG) +template +void +Object_merge_map::initialize_input_to_output_map<64>( + unsigned int shndx, + elfcpp::Elf_types<64>::Elf_Addr starting_address, + Unordered_map::Elf_Addr>*); +#endif + +} // End namespace gold. diff --git a/binutils-2.25/gold/merge.h b/binutils-2.25/gold/merge.h new file mode 100644 index 00000000..92c634a5 --- /dev/null +++ b/binutils-2.25/gold/merge.h @@ -0,0 +1,574 @@ +// merge.h -- handle section merging for gold -*- C++ -*- + +// Copyright 2006, 2007, 2008, 2010 Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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. + +#ifndef GOLD_MERGE_H +#define GOLD_MERGE_H + +#include +#include +#include + +#include "stringpool.h" +#include "output.h" + +namespace gold +{ + +class Merge_map; + +// For each object with merge sections, we store an Object_merge_map. +// This is used to map locations in input sections to a merged output +// section. The output section itself is not recorded here--it can be +// found in the output_sections_ field of the Object. + +class Object_merge_map +{ + public: + Object_merge_map() + : first_shnum_(-1U), first_map_(), + second_shnum_(-1U), second_map_(), + section_merge_maps_() + { } + + ~Object_merge_map(); + + // Add a mapping for MERGE_MAP, for the bytes from OFFSET to OFFSET + // + LENGTH in the input section SHNDX to OUTPUT_OFFSET in the + // output section. An OUTPUT_OFFSET of -1 means that the bytes are + // discarded. OUTPUT_OFFSET is relative to the start of the merged + // data in the output section. + void + add_mapping(const Merge_map*, unsigned int shndx, section_offset_type offset, + section_size_type length, section_offset_type output_offset); + + // Get the output offset for an input address. MERGE_MAP is the map + // we are looking for, or NULL if we don't care. The input address + // is at offset OFFSET in section SHNDX. This sets *OUTPUT_OFFSET + // to the offset in the output section; this will be -1 if the bytes + // are not being copied to the output. This returns true if the + // mapping is known, false otherwise. *OUTPUT_OFFSET is relative to + // the start of the merged data in the output section. + bool + get_output_offset(const Merge_map*, unsigned int shndx, + section_offset_type offset, + section_offset_type* output_offset); + + // Return whether this is the merge map for section SHNDX. + bool + is_merge_section_for(const Merge_map*, unsigned int shndx); + + // Initialize an mapping from input offsets to output addresses for + // section SHNDX. STARTING_ADDRESS is the output address of the + // merged section. + template + void + initialize_input_to_output_map( + unsigned int shndx, + typename elfcpp::Elf_types::Elf_Addr starting_address, + Unordered_map::Elf_Addr>*); + + private: + // Map input section offsets to a length and an output section + // offset. An output section offset of -1 means that this part of + // the input section is being discarded. + struct Input_merge_entry + { + // The offset in the input section. + section_offset_type input_offset; + // The length. + section_size_type length; + // The offset in the output section. + section_offset_type output_offset; + }; + + // A less-than comparison routine for Input_merge_entry. + struct Input_merge_compare + { + bool + operator()(const Input_merge_entry& i1, const Input_merge_entry& i2) const + { return i1.input_offset < i2.input_offset; } + }; + + // A list of entries for a particular input section. + struct Input_merge_map + { + typedef std::vector Entries; + + // We store these with the Relobj, and we look them up by input + // section. It is possible to have two different merge maps + // associated with a single output section. For example, this + // happens routinely with .rodata, when merged string constants + // and merged fixed size constants are both put into .rodata. The + // output offset that we store is not the offset from the start of + // the output section; it is the offset from the start of the + // merged data in the output section. That means that the caller + // is going to add the offset of the merged data within the output + // section, which means that the caller needs to know which set of + // merged data it found the entry in. So it's not enough to find + // this data based on the input section and the output section; we + // also have to find it based on a set of merged data in the + // output section. In order to verify that we are looking at the + // right data, we store a pointer to the Merge_map here, and we + // pass in a pointer when looking at the data. If we are asked to + // look up information for a different Merge_map, we report that + // we don't have it, rather than trying a lookup and returning an + // answer which will receive the wrong offset. + const Merge_map* merge_map; + // The list of mappings. + Entries entries; + // Whether the ENTRIES field is sorted by input_offset. + bool sorted; + + Input_merge_map() + : merge_map(NULL), entries(), sorted(true) + { } + }; + + // Map input section indices to merge maps. + typedef std::map Section_merge_maps; + + // Return a pointer to the Input_merge_map to use for the input + // section SHNDX, or NULL. + Input_merge_map* + get_input_merge_map(unsigned int shndx); + + // Get or make the Input_merge_map to use for the section SHNDX + // with MERGE_MAP. + Input_merge_map* + get_or_make_input_merge_map(const Merge_map* merge_map, unsigned int shndx); + + // Any given object file will normally only have a couple of input + // sections with mergeable contents. So we keep the first two input + // section numbers inline, and push any further ones into a map. A + // value of -1U in first_shnum_ or second_shnum_ means that we don't + // have a corresponding entry. + unsigned int first_shnum_; + Input_merge_map first_map_; + unsigned int second_shnum_; + Input_merge_map second_map_; + Section_merge_maps section_merge_maps_; +}; + +// This class manages mappings from input sections to offsets in an +// output section. This is used where input sections are merged. The +// actual data is stored in fields in Object. + +class Merge_map +{ + public: + Merge_map() + { } + + // Add a mapping for the bytes from OFFSET to OFFSET + LENGTH in the + // input section SHNDX in object OBJECT to OUTPUT_OFFSET in the + // output section. An OUTPUT_OFFSET of -1 means that the bytes are + // discarded. OUTPUT_OFFSET is not the offset from the start of the + // output section, it is the offset from the start of the merged + // data within the output section. + void + add_mapping(Relobj* object, unsigned int shndx, + section_offset_type offset, section_size_type length, + section_offset_type output_offset); + + // Return the output offset for an input address. The input address + // is at offset OFFSET in section SHNDX in OBJECT. This sets + // *OUTPUT_OFFSET to the offset in the output section; this will be + // -1 if the bytes are not being copied to the output. This returns + // true if the mapping is known, false otherwise. This returns the + // value stored by add_mapping, namely the offset from the start of + // the merged data within the output section. + bool + get_output_offset(const Relobj* object, unsigned int shndx, + section_offset_type offset, + section_offset_type* output_offset) const; + + // Return whether this is the merge mapping for section SHNDX in + // OBJECT. This should return true when get_output_offset would + // return true for some input offset. + bool + is_merge_section_for(const Relobj* object, unsigned int shndx) const; +}; + +// A general class for SHF_MERGE data, to hold functions shared by +// fixed-size constant data and string data. + +class Output_merge_base : public Output_section_data +{ + public: + Output_merge_base(uint64_t entsize, uint64_t addralign) + : Output_section_data(addralign), merge_map_(), entsize_(entsize), + keeps_input_sections_(false), first_relobj_(NULL), first_shndx_(-1), + input_sections_() + { } + + // Return the entry size. + uint64_t + entsize() const + { return this->entsize_; } + + // Whether this is a merge string section. This is only true of + // Output_merge_string. + bool + is_string() + { return this->do_is_string(); } + + // Whether this keeps input sections. + bool + keeps_input_sections() const + { return this->keeps_input_sections_; } + + // Set the keeps-input-sections flag. This is virtual so that sub-classes + // can perform additional checks. + void + set_keeps_input_sections() + { this->do_set_keeps_input_sections(); } + + // Return the object of the first merged input section. This used + // for script processing. This is NULL if merge section is empty. + Relobj* + first_relobj() const + { return this->first_relobj_; } + + // Return the section index of the first merged input section. This + // is used for script processing. This is valid only if merge section + // is not valid. + unsigned int + first_shndx() const + { + gold_assert(this->first_relobj_ != NULL); + return this->first_shndx_; + } + + // Set of merged input sections. + typedef Unordered_set Input_sections; + + // Beginning of merged input sections. + Input_sections::const_iterator + input_sections_begin() const + { + gold_assert(this->keeps_input_sections_); + return this->input_sections_.begin(); + } + + // Beginning of merged input sections. + Input_sections::const_iterator + input_sections_end() const + { + gold_assert(this->keeps_input_sections_); + return this->input_sections_.end(); + } + + protected: + // Return the output offset for an input offset. + bool + do_output_offset(const Relobj* object, unsigned int shndx, + section_offset_type offset, + section_offset_type* poutput) const; + + // Return whether this is the merge section for an input section. + bool + do_is_merge_section_for(const Relobj*, unsigned int shndx) const; + + // Add a mapping from an OFFSET in input section SHNDX in object + // OBJECT to an OUTPUT_OFFSET in the output section. OUTPUT_OFFSET + // is the offset from the start of the merged data in the output + // section. + void + add_mapping(Relobj* object, unsigned int shndx, section_offset_type offset, + section_size_type length, section_offset_type output_offset) + { + this->merge_map_.add_mapping(object, shndx, offset, length, output_offset); + } + + // This may be overridden by the child class. + virtual bool + do_is_string() + { return false; } + + // This may be overridden by the child class. + virtual void + do_set_keeps_input_sections() + { this->keeps_input_sections_ = true; } + + // Record the merged input section for script processing. + void + record_input_section(Relobj* relobj, unsigned int shndx); + + private: + // A mapping from input object/section/offset to offset in output + // section. + Merge_map merge_map_; + // The entry size. For fixed-size constants, this is the size of + // the constants. For strings, this is the size of a character. + uint64_t entsize_; + // Whether we keep input sections. + bool keeps_input_sections_; + // Object of the first merged input section. We use this for script + // processing. + Relobj* first_relobj_; + // Section index of the first merged input section. + unsigned int first_shndx_; + // Input sections. We only keep them is keeps_input_sections_ is true. + Input_sections input_sections_; +}; + +// Handle SHF_MERGE sections with fixed-size constant data. + +class Output_merge_data : public Output_merge_base +{ + public: + Output_merge_data(uint64_t entsize, uint64_t addralign) + : Output_merge_base(entsize, addralign), p_(NULL), len_(0), alc_(0), + input_count_(0), + hashtable_(128, Merge_data_hash(this), Merge_data_eq(this)) + { } + + protected: + // Add an input section. + bool + do_add_input_section(Relobj* object, unsigned int shndx); + + // Set the final data size. + void + set_final_data_size(); + + // Write the data to the file. + void + do_write(Output_file*); + + // Write the data to a buffer. + void + do_write_to_buffer(unsigned char*); + + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _("** merge constants")); } + + // Print merge stats to stderr. + void + do_print_merge_stats(const char* section_name); + + // Set keeps-input-sections flag. + void + do_set_keeps_input_sections() + { + gold_assert(this->input_count_ == 0); + Output_merge_base::do_set_keeps_input_sections(); + } + + private: + // We build a hash table of the fixed-size constants. Each constant + // is stored as a pointer into the section data we are accumulating. + + // A key in the hash table. This is an offset in the section + // contents we are building. + typedef section_offset_type Merge_data_key; + + // Compute the hash code. To do this we need a pointer back to the + // object holding the data. + class Merge_data_hash + { + public: + Merge_data_hash(const Output_merge_data* pomd) + : pomd_(pomd) + { } + + size_t + operator()(Merge_data_key) const; + + private: + const Output_merge_data* pomd_; + }; + + friend class Merge_data_hash; + + // Compare two entries in the hash table for equality. To do this + // we need a pointer back to the object holding the data. Note that + // we now have a pointer to the object stored in two places in the + // hash table. Fixing this would require specializing the hash + // table, which would be hard to do portably. + class Merge_data_eq + { + public: + Merge_data_eq(const Output_merge_data* pomd) + : pomd_(pomd) + { } + + bool + operator()(Merge_data_key k1, Merge_data_key k2) const; + + private: + const Output_merge_data* pomd_; + }; + + friend class Merge_data_eq; + + // The type of the hash table. + typedef Unordered_set + Merge_data_hashtable; + + // Given a hash table key, which is just an offset into the section + // data, return a pointer to the corresponding constant. + const unsigned char* + constant(Merge_data_key k) const + { + gold_assert(k >= 0 && k < static_cast(this->len_)); + return this->p_ + k; + } + + // Add a constant to the output. + void + add_constant(const unsigned char*); + + // The accumulated data. + unsigned char* p_; + // The length of the accumulated data. + section_size_type len_; + // The size of the allocated buffer. + section_size_type alc_; + // The number of entries seen in input files. + size_t input_count_; + // The hash table. + Merge_data_hashtable hashtable_; +}; + +// Handle SHF_MERGE sections with string data. This is a template +// based on the type of the characters in the string. + +template +class Output_merge_string : public Output_merge_base +{ + public: + Output_merge_string(uint64_t addralign) + : Output_merge_base(sizeof(Char_type), addralign), stringpool_(addralign), + merged_strings_lists_(), input_count_(0), input_size_(0) + { + this->stringpool_.set_no_zero_null(); + } + + protected: + // Add an input section. + bool + do_add_input_section(Relobj* object, unsigned int shndx); + + // Do all the final processing after the input sections are read in. + // Returns the final data size. + section_size_type + finalize_merged_data(); + + // Set the final data size. + void + set_final_data_size(); + + // Write the data to the file. + void + do_write(Output_file*); + + // Write the data to a buffer. + void + do_write_to_buffer(unsigned char*); + + // Write to a map file. + void + do_print_to_mapfile(Mapfile* mapfile) const + { mapfile->print_output_data(this, _("** merge strings")); } + + // Print merge stats to stderr. + void + do_print_merge_stats(const char* section_name); + + // Writes the stringpool to a buffer. + void + stringpool_to_buffer(unsigned char* buffer, section_size_type buffer_size) + { this->stringpool_.write_to_buffer(buffer, buffer_size); } + + // Clears all the data in the stringpool, to save on memory. + void + clear_stringpool() + { this->stringpool_.clear(); } + + // Whether this is a merge string section. + virtual bool + do_is_string() + { return true; } + + // Set keeps-input-sections flag. + void + do_set_keeps_input_sections() + { + gold_assert(this->input_count_ == 0); + Output_merge_base::do_set_keeps_input_sections(); + } + + private: + // The name of the string type, for stats. + const char* + string_name(); + + // As we see input sections, we build a mapping from object, section + // index and offset to strings. + struct Merged_string + { + // The offset in the input section. + section_offset_type offset; + // The key in the Stringpool. + Stringpool::Key stringpool_key; + + Merged_string(section_offset_type offseta, Stringpool::Key stringpool_keya) + : offset(offseta), stringpool_key(stringpool_keya) + { } + }; + + typedef std::vector Merged_strings; + + struct Merged_strings_list + { + // The input object where the strings were found. + Relobj* object; + // The input section in the input object. + unsigned int shndx; + // The list of merged strings. + Merged_strings merged_strings; + + Merged_strings_list(Relobj* objecta, unsigned int shndxa) + : object(objecta), shndx(shndxa), merged_strings() + { } + }; + + typedef std::vector Merged_strings_lists; + + // As we see the strings, we add them to a Stringpool. + Stringpool_template stringpool_; + // Map from a location in an input object to an entry in the + // Stringpool. + Merged_strings_lists merged_strings_lists_; + // The number of entries seen in input files. + size_t input_count_; + // The total size of input sections. + size_t input_size_; +}; + +} // End namespace gold. + +#endif // !defined(GOLD_MERGE_H) diff --git a/binutils-2.25/gold/mremap.c b/binutils-2.25/gold/mremap.c new file mode 100644 index 00000000..e1656341 --- /dev/null +++ b/binutils-2.25/gold/mremap.c @@ -0,0 +1,87 @@ +/* mremap.c -- version of mremap for gold. */ + +/* Copyright 2009, 2011 Free Software Foundation, Inc. + Written by Ian Lance Taylor . + + 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 "config.h" +#include "ansidecl.h" + +#include +#include +#include + +#ifdef HAVE_SYS_MMAN_H +#include +#endif + +extern void *gold_mremap (void *, size_t, size_t, int); + +#ifdef HAVE_MMAP + +/* This file implements mremap for systems which don't have it. The + gold code requires support for mmap. However, there are systems + which have mmap but not mremap. This is not a general replacement + for mremap; it only supports the features which are required for + gold. In particular, we assume that the MREMAP_MAYMOVE flag is + set. */ + +/* Some BSD systems still use MAP_ANON instead of MAP_ANONYMOUS. */ + +#ifndef MAP_ANONYMOUS +# define MAP_ANONYMOUS MAP_ANON +#endif + +void * +gold_mremap (void *old_address, size_t old_size, size_t new_size, + int flags ATTRIBUTE_UNUSED) +{ + void *ret; + + ret = mmap (0, new_size, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + if (ret == MAP_FAILED) + return ret; + memcpy (ret, old_address, + old_size < new_size ? old_size : new_size); + (void) munmap (old_address, old_size); + return ret; +} + +#else /* !defined(HAVE_MMAP) */ + +#ifndef MAP_FAILED +#define MAP_FAILED ((void *) -1) +#endif + +#ifndef ENOSYS +#define ENOSYS EINVAL +#endif + +void * +gold_mremap (void *old_address ATTRIBUTE_UNUSED, + size_t old_size ATTRIBUTE_UNUSED, + size_t new_size ATTRIBUTE_UNUSED, + int flags ATTRIBUTE_UNUSED) +{ + errno = ENOSYS; + return MAP_FAILED; +} + +#endif /* !defined(HAVE_MMAP) */ diff --git a/binutils-2.25/gold/nacl.cc b/binutils-2.25/gold/nacl.cc new file mode 100644 index 00000000..b22248c4 --- /dev/null +++ b/binutils-2.25/gold/nacl.cc @@ -0,0 +1,47 @@ +// 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 +#include "libiberty.h" + +#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/binutils-2.25/gold/nacl.h b/binutils-2.25/gold/nacl.h new file mode 100644 index 00000000..323f8043 --- /dev/null +++ b/binutils-2.25/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, true, 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 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* 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* 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 + bool + do_recognize_nacl_file(Input_file* input_file, off_t offset) + { + Sniff_file file(input_file, offset); + elfcpp::Elf_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/binutils-2.25/gold/object.cc b/binutils-2.25/gold/object.cc new file mode 100644 index 00000000..c98b3c5a --- /dev/null +++ b/binutils-2.25/gold/object.cc @@ -0,0 +1,3331 @@ +// object.cc -- support for an object file for linking in gold + +// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 +// Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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 +#include +#include +#include "demangle.h" +#include "libiberty.h" + +#include "gc.h" +#include "target-select.h" +#include "dwarf_reader.h" +#include "layout.h" +#include "output.h" +#include "symtab.h" +#include "cref.h" +#include "reloc.h" +#include "object.h" +#include "dynobj.h" +#include "plugin.h" +#include "compressed_output.h" +#include "incremental.h" + +namespace gold +{ + +// Struct Read_symbols_data. + +// Destroy any remaining File_view objects and buffers of decompressed +// sections. + +Read_symbols_data::~Read_symbols_data() +{ + if (this->section_headers != NULL) + delete this->section_headers; + if (this->section_names != NULL) + delete this->section_names; + if (this->symbols != NULL) + delete this->symbols; + if (this->symbol_names != NULL) + delete this->symbol_names; + if (this->versym != NULL) + delete this->versym; + if (this->verdef != NULL) + delete this->verdef; + if (this->verneed != NULL) + delete this->verneed; +} + +// Class Xindex. + +// Initialize the symtab_xindex_ array. Find the SHT_SYMTAB_SHNDX +// section and read it in. SYMTAB_SHNDX is the index of the symbol +// table we care about. + +template +void +Xindex::initialize_symtab_xindex(Object* object, unsigned int symtab_shndx) +{ + if (!this->symtab_xindex_.empty()) + return; + + gold_assert(symtab_shndx != 0); + + // Look through the sections in reverse order, on the theory that it + // is more likely to be near the end than the beginning. + unsigned int i = object->shnum(); + while (i > 0) + { + --i; + if (object->section_type(i) == elfcpp::SHT_SYMTAB_SHNDX + && this->adjust_shndx(object->section_link(i)) == symtab_shndx) + { + this->read_symtab_xindex(object, i, NULL); + return; + } + } + + object->error(_("missing SHT_SYMTAB_SHNDX section")); +} + +// Read in the symtab_xindex_ array, given the section index of the +// SHT_SYMTAB_SHNDX section. If PSHDRS is not NULL, it points at the +// section headers. + +template +void +Xindex::read_symtab_xindex(Object* object, unsigned int xindex_shndx, + const unsigned char* pshdrs) +{ + section_size_type bytecount; + const unsigned char* contents; + if (pshdrs == NULL) + contents = object->section_contents(xindex_shndx, &bytecount, false); + else + { + const unsigned char* p = (pshdrs + + (xindex_shndx + * elfcpp::Elf_sizes::shdr_size)); + typename elfcpp::Shdr shdr(p); + bytecount = convert_to_section_size_type(shdr.get_sh_size()); + contents = object->get_view(shdr.get_sh_offset(), bytecount, true, false); + } + + gold_assert(this->symtab_xindex_.empty()); + this->symtab_xindex_.reserve(bytecount / 4); + for (section_size_type i = 0; i < bytecount; i += 4) + { + unsigned int shndx = elfcpp::Swap<32, big_endian>::readval(contents + i); + // We preadjust the section indexes we save. + this->symtab_xindex_.push_back(this->adjust_shndx(shndx)); + } +} + +// Symbol symndx has a section of SHN_XINDEX; return the real section +// index. + +unsigned int +Xindex::sym_xindex_to_shndx(Object* object, unsigned int symndx) +{ + if (symndx >= this->symtab_xindex_.size()) + { + object->error(_("symbol %u out of range for SHT_SYMTAB_SHNDX section"), + symndx); + return elfcpp::SHN_UNDEF; + } + unsigned int shndx = this->symtab_xindex_[symndx]; + if (shndx < elfcpp::SHN_LORESERVE || shndx >= object->shnum()) + { + object->error(_("extended index for symbol %u out of range: %u"), + symndx, shndx); + return elfcpp::SHN_UNDEF; + } + return shndx; +} + +// Class Object. + +// Report an error for this object file. This is used by the +// elfcpp::Elf_file interface, and also called by the Object code +// itself. + +void +Object::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->name().c_str(), buf); + free(buf); +} + +// Return a view of the contents of a section. + +const unsigned char* +Object::section_contents(unsigned int shndx, section_size_type* plen, + bool cache) +{ return this->do_section_contents(shndx, plen, cache); } + +// Read the section data into SD. This is code common to Sized_relobj_file +// and Sized_dynobj, so we put it into Object. + +template +void +Object::read_section_data(elfcpp::Elf_file* elf_file, + Read_symbols_data* sd) +{ + const int shdr_size = elfcpp::Elf_sizes::shdr_size; + + // Read the section headers. + const off_t shoff = elf_file->shoff(); + const unsigned int shnum = this->shnum(); + sd->section_headers = this->get_lasting_view(shoff, shnum * shdr_size, + true, true); + + // Read the section names. + const unsigned char* pshdrs = sd->section_headers->data(); + const unsigned char* pshdrnames = pshdrs + elf_file->shstrndx() * shdr_size; + typename elfcpp::Shdr shdrnames(pshdrnames); + + if (shdrnames.get_sh_type() != elfcpp::SHT_STRTAB) + this->error(_("section name section has wrong type: %u"), + static_cast(shdrnames.get_sh_type())); + + sd->section_names_size = + convert_to_section_size_type(shdrnames.get_sh_size()); + sd->section_names = this->get_lasting_view(shdrnames.get_sh_offset(), + sd->section_names_size, false, + false); +} + +// If NAME is the name of a special .gnu.warning section, arrange for +// the warning to be issued. SHNDX is the section index. Return +// whether it is a warning section. + +bool +Object::handle_gnu_warning_section(const char* name, unsigned int shndx, + Symbol_table* symtab) +{ + const char warn_prefix[] = ".gnu.warning."; + const int warn_prefix_len = sizeof warn_prefix - 1; + if (strncmp(name, warn_prefix, warn_prefix_len) == 0) + { + // Read the section contents to get the warning text. It would + // be nicer if we only did this if we have to actually issue a + // warning. Unfortunately, warnings are issued as we relocate + // sections. That means that we can not lock the object then, + // as we might try to issue the same warning multiple times + // simultaneously. + section_size_type len; + const unsigned char* contents = this->section_contents(shndx, &len, + false); + if (len == 0) + { + const char* warning = name + warn_prefix_len; + contents = reinterpret_cast(warning); + len = strlen(warning); + } + std::string warning(reinterpret_cast(contents), len); + symtab->add_warning(name + warn_prefix_len, this, warning); + return true; + } + return false; +} + +// If NAME is the name of the special section which indicates that +// this object was compiled with -fsplit-stack, mark it accordingly. + +bool +Object::handle_split_stack_section(const char* name) +{ + if (strcmp(name, ".note.GNU-split-stack") == 0) + { + this->uses_split_stack_ = true; + return true; + } + if (strcmp(name, ".note.GNU-no-split-stack") == 0) + { + this->has_no_split_stack_ = true; + return true; + } + return false; +} + +// 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 +// collection. + +void +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)]; + 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]; + memcpy(gc_sd->section_names_data, sd->section_names->data(), + 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]; + memcpy(gc_sd->symbols_data, sd->symbols->data(), + sd->symbols_size); + } + else + { + gc_sd->symbols_data = NULL; + } + gc_sd->symbols_size = sd->symbols_size; + gc_sd->external_symbols_offset = sd->external_symbols_offset; + if (sd->symbol_names != NULL) + { + gc_sd->symbol_names_data = + new unsigned char[sd->symbol_names_size]; + memcpy(gc_sd->symbol_names_data, sd->symbol_names->data(), + sd->symbol_names_size); + } + else + { + gc_sd->symbol_names_data = NULL; + } + gc_sd->symbol_names_size = sd->symbol_names_size; +} + +// This function determines if a particular section name must be included +// in the link. This is used during garbage collection to determine the +// roots of the worklist. + +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")) + || (is_prefix_of(".sdata", name) + && strstr(name, "personality")) + || (is_prefix_of(".gnu.linkonce.d", name) + && strstr(name, "personality"))) + { + return true; + } + return false; +} + +// Finalize the incremental relocation information. Allocates a block +// of relocation entries for each symbol, and sets the reloc_bases_ +// array to point to the first entry in each block. If CLEAR_COUNTS +// is TRUE, also clear the per-symbol relocation counters. + +void +Relobj::finalize_incremental_relocs(Layout* layout, bool clear_counts) +{ + unsigned int nsyms = this->get_global_symbols()->size(); + this->reloc_bases_ = new unsigned int[nsyms]; + + gold_assert(this->reloc_bases_ != NULL); + gold_assert(layout->incremental_inputs() != NULL); + + unsigned int rindex = layout->incremental_inputs()->get_reloc_count(); + for (unsigned int i = 0; i < nsyms; ++i) + { + this->reloc_bases_[i] = rindex; + rindex += this->reloc_counts_[i]; + if (clear_counts) + this->reloc_counts_[i] = 0; + } + layout->incremental_inputs()->set_reloc_count(rindex); +} + +// Class Sized_relobj. + +// Iterate over local symbols, calling a visitor class V for each GOT offset +// associated with a local symbol. + +template +void +Sized_relobj::do_for_all_local_got_entries( + Got_offset_list::Visitor* v) const +{ + unsigned int nsyms = this->local_symbol_count(); + for (unsigned int i = 0; i < nsyms; i++) + { + Local_got_offsets::const_iterator p = this->local_got_offsets_.find(i); + if (p != this->local_got_offsets_.end()) + { + const Got_offset_list* got_offsets = p->second; + got_offsets->for_all_got_offsets(v); + } + } +} + +// Get the address of an output section. + +template +uint64_t +Sized_relobj::do_output_section_address( + unsigned int shndx) +{ + // If the input file is linked as --just-symbols, the output + // section address is the input section address. + if (this->just_symbols()) + return this->section_address(shndx); + + const Output_section* os = this->do_output_section(shndx); + gold_assert(os != NULL); + return os->address(); +} + +// Class Sized_relobj_file. + +template +Sized_relobj_file::Sized_relobj_file( + const std::string& name, + Input_file* input_file, + off_t offset, + const elfcpp::Ehdr& ehdr) + : Sized_relobj(name, input_file, offset), + elf_file_(this, ehdr), + symtab_shndx_(-1U), + local_symbol_count_(0), + output_local_symbol_count_(0), + output_local_dynsym_count_(0), + symbols_(), + defined_count_(0), + local_symbol_offset_(0), + local_dynsym_offset_(0), + local_values_(), + local_plt_offsets_(), + kept_comdat_sections_(), + has_eh_frame_(false), + discarded_eh_frame_shndx_(-1U), + deferred_layout_(), + deferred_layout_relocs_(), + compressed_sections_() +{ + this->e_type_ = ehdr.get_e_type(); +} + +template +Sized_relobj_file::~Sized_relobj_file() +{ +} + +// Set up an object file based on the file header. This sets up the +// section information. + +template +void +Sized_relobj_file::do_setup() +{ + const unsigned int shnum = this->elf_file_.shnum(); + this->set_shnum(shnum); +} + +// Find the SHT_SYMTAB section, given the section headers. The ELF +// standard says that maybe in the future there can be more than one +// SHT_SYMTAB section. Until somebody figures out how that could +// work, we assume there is only one. + +template +void +Sized_relobj_file::find_symtab(const unsigned char* pshdrs) +{ + const unsigned int shnum = this->shnum(); + this->symtab_shndx_ = 0; + if (shnum > 0) + { + // Look through the sections in reverse order, since gas tends + // to put the symbol table at the end. + const unsigned char* p = pshdrs + shnum * This::shdr_size; + unsigned int i = shnum; + unsigned int xindex_shndx = 0; + unsigned int xindex_link = 0; + while (i > 0) + { + --i; + p -= This::shdr_size; + typename This::Shdr shdr(p); + if (shdr.get_sh_type() == elfcpp::SHT_SYMTAB) + { + this->symtab_shndx_ = i; + if (xindex_shndx > 0 && xindex_link == i) + { + Xindex* xindex = + new Xindex(this->elf_file_.large_shndx_offset()); + xindex->read_symtab_xindex(this, + xindex_shndx, + pshdrs); + this->set_xindex(xindex); + } + break; + } + + // Try to pick up the SHT_SYMTAB_SHNDX section, if there is + // one. This will work if it follows the SHT_SYMTAB + // section. + if (shdr.get_sh_type() == elfcpp::SHT_SYMTAB_SHNDX) + { + xindex_shndx = i; + xindex_link = this->adjust_shndx(shdr.get_sh_link()); + } + } + } +} + +// Return the Xindex structure to use for object with lots of +// sections. + +template +Xindex* +Sized_relobj_file::do_initialize_xindex() +{ + gold_assert(this->symtab_shndx_ != -1U); + Xindex* xindex = new Xindex(this->elf_file_.large_shndx_offset()); + xindex->initialize_symtab_xindex(this, this->symtab_shndx_); + return xindex; +} + +// Return whether SHDR has the right type and flags to be a GNU +// .eh_frame section. + +template +bool +Sized_relobj_file::check_eh_frame_flags( + const elfcpp::Shdr* shdr) const +{ + elfcpp::Elf_Word sh_type = shdr->get_sh_type(); + return ((sh_type == elfcpp::SHT_PROGBITS + || sh_type == elfcpp::SHT_X86_64_UNWIND) + && (shdr->get_sh_flags() & elfcpp::SHF_ALLOC) != 0); +} + +// Find the section header with the given name. + +template +const unsigned char* +Object::find_shdr( + const unsigned char* pshdrs, + const char* name, + const char* names, + section_size_type names_size, + const unsigned char* hdr) const +{ + const int shdr_size = elfcpp::Elf_sizes::shdr_size; + const unsigned int shnum = this->shnum(); + const unsigned char* hdr_end = pshdrs + shdr_size * shnum; + size_t sh_name = 0; + + while (1) + { + if (hdr) + { + // We found HDR last time we were called, continue looking. + typename elfcpp::Shdr shdr(hdr); + sh_name = shdr.get_sh_name(); + } + else + { + // Look for the next occurrence of NAME in NAMES. + // The fact that .shstrtab produced by current GNU tools is + // string merged means we shouldn't have both .not.foo and + // .foo in .shstrtab, and multiple .foo sections should all + // have the same sh_name. However, this is not guaranteed + // by the ELF spec and not all ELF object file producers may + // be so clever. + size_t len = strlen(name) + 1; + const char *p = sh_name ? names + sh_name + len : names; + p = reinterpret_cast(memmem(p, names_size - (p - names), + name, len)); + if (p == NULL) + return NULL; + sh_name = p - names; + hdr = pshdrs; + if (sh_name == 0) + return hdr; + } + + hdr += shdr_size; + while (hdr < hdr_end) + { + typename elfcpp::Shdr shdr(hdr); + if (shdr.get_sh_name() == sh_name) + return hdr; + hdr += shdr_size; + } + hdr = NULL; + if (sh_name == 0) + return hdr; + } +} + +// Return whether there is a GNU .eh_frame section, given the section +// headers and the section names. + +template +bool +Sized_relobj_file::find_eh_frame( + const unsigned char* pshdrs, + const char* names, + section_size_type names_size) const +{ + const unsigned char* s = NULL; + + while (1) + { + s = this->template find_shdr(pshdrs, ".eh_frame", + names, names_size, s); + if (s == NULL) + return false; + + typename This::Shdr shdr(s); + if (this->check_eh_frame_flags(&shdr)) + return true; + } +} + +// Return TRUE if this is a section whose contents will be needed in the +// Add_symbols task. This function is only called for sections that have +// already passed the test in is_compressed_debug_section(), so we know +// that the section name begins with ".zdebug". + +static bool +need_decompressed_section(const char* name) +{ + // Skip over the ".zdebug" and a quick check for the "_". + name += 7; + if (*name++ != '_') + return false; + +#ifdef ENABLE_THREADS + // Decompressing these sections now will help only if we're + // multithreaded. + if (parameters->options().threads()) + { + // We will need .zdebug_str if this is not an incremental link + // (i.e., we are processing string merge sections) or if we need + // to build a gdb index. + if ((!parameters->incremental() || parameters->options().gdb_index()) + && strcmp(name, "str") == 0) + return true; + + // We will need these other sections when building a gdb index. + if (parameters->options().gdb_index() + && (strcmp(name, "info") == 0 + || strcmp(name, "types") == 0 + || strcmp(name, "pubnames") == 0 + || strcmp(name, "pubtypes") == 0 + || strcmp(name, "ranges") == 0 + || strcmp(name, "abbrev") == 0)) + return true; + } +#endif + + // Even when single-threaded, we will need .zdebug_str if this is + // not an incremental link and we are building a gdb index. + // Otherwise, we would decompress the section twice: once for + // string merge processing, and once for building the gdb index. + if (!parameters->incremental() + && parameters->options().gdb_index() + && strcmp(name, "str") == 0) + return true; + + return false; +} + +// Build a table for any compressed debug sections, mapping each section index +// to the uncompressed size and (if needed) the decompressed contents. + +template +Compressed_section_map* +build_compressed_section_map( + const unsigned char* pshdrs, + unsigned int shnum, + const char* names, + section_size_type names_size, + Sized_relobj_file* obj) +{ + Compressed_section_map* uncompressed_map = new Compressed_section_map(); + const unsigned int shdr_size = elfcpp::Elf_sizes::shdr_size; + const unsigned char* p = pshdrs + shdr_size; + + for (unsigned int i = 1; i < shnum; ++i, p += shdr_size) + { + typename elfcpp::Shdr shdr(p); + if (shdr.get_sh_type() == elfcpp::SHT_PROGBITS + && (shdr.get_sh_flags() & elfcpp::SHF_ALLOC) == 0) + { + if (shdr.get_sh_name() >= names_size) + { + obj->error(_("bad section name offset for section %u: %lu"), + i, static_cast(shdr.get_sh_name())); + continue; + } + + const char* name = names + shdr.get_sh_name(); + if (is_compressed_debug_section(name)) + { + section_size_type len; + const unsigned char* contents = + obj->section_contents(i, &len, false); + uint64_t uncompressed_size = get_uncompressed_size(contents, len); + Compressed_section_info info; + info.size = convert_to_section_size_type(uncompressed_size); + info.contents = NULL; + if (uncompressed_size != -1ULL) + { + unsigned char* uncompressed_data = NULL; + if (need_decompressed_section(name)) + { + uncompressed_data = new unsigned char[uncompressed_size]; + if (decompress_input_section(contents, len, + uncompressed_data, + uncompressed_size)) + info.contents = uncompressed_data; + else + delete[] uncompressed_data; + } + (*uncompressed_map)[i] = info; + } + } + } + } + return uncompressed_map; +} + +// Stash away info for a number of special sections. +// Return true if any of the sections found require local symbols to be read. + +template +bool +Sized_relobj_file::do_find_special_sections( + Read_symbols_data* sd) +{ + const unsigned char* const pshdrs = sd->section_headers->data(); + const unsigned char* namesu = sd->section_names->data(); + const char* names = reinterpret_cast(namesu); + + if (this->find_eh_frame(pshdrs, names, sd->section_names_size)) + 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, + sd->section_names_size, this); + return (this->has_eh_frame_ + || (!parameters->options().relocatable() + && parameters->options().gdb_index() + && (memmem(names, sd->section_names_size, "debug_info", 12) == 0 + || memmem(names, sd->section_names_size, "debug_types", + 13) == 0))); +} + +// Read the sections and symbols from an object file. + +template +void +Sized_relobj_file::do_read_symbols(Read_symbols_data* sd) +{ + this->read_section_data(&this->elf_file_, sd); + + const unsigned char* const pshdrs = sd->section_headers->data(); + + this->find_symtab(pshdrs); + + bool need_local_symbols = this->do_find_special_sections(sd); + + sd->symbols = NULL; + sd->symbols_size = 0; + sd->external_symbols_offset = 0; + sd->symbol_names = NULL; + sd->symbol_names_size = 0; + + if (this->symtab_shndx_ == 0) + { + // No symbol table. Weird but legal. + return; + } + + // Get the symbol table section header. + typename This::Shdr symtabshdr(pshdrs + + this->symtab_shndx_ * This::shdr_size); + gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB); + + // If this object has a .eh_frame section, or if building a .gdb_index + // section and there is debug info, we need all the symbols. + // Otherwise we only need the external symbols. While it would be + // simpler to just always read all the symbols, I've seen object + // files with well over 2000 local symbols, which for a 64-bit + // object file format is over 5 pages that we don't need to read + // now. + + const int sym_size = This::sym_size; + const unsigned int loccount = symtabshdr.get_sh_info(); + this->local_symbol_count_ = loccount; + this->local_values_.resize(loccount); + section_offset_type locsize = loccount * sym_size; + off_t dataoff = symtabshdr.get_sh_offset(); + section_size_type datasize = + convert_to_section_size_type(symtabshdr.get_sh_size()); + off_t extoff = dataoff + locsize; + section_size_type extsize = datasize - locsize; + + off_t readoff = need_local_symbols ? dataoff : extoff; + section_size_type readsize = need_local_symbols ? datasize : extsize; + + if (readsize == 0) + { + // No external symbols. Also weird but also legal. + return; + } + + File_view* fvsymtab = this->get_lasting_view(readoff, readsize, true, false); + + // Read the section header for the symbol names. + unsigned int strtab_shndx = this->adjust_shndx(symtabshdr.get_sh_link()); + if (strtab_shndx >= this->shnum()) + { + this->error(_("invalid symbol table name index: %u"), strtab_shndx); + return; + } + typename This::Shdr strtabshdr(pshdrs + strtab_shndx * This::shdr_size); + if (strtabshdr.get_sh_type() != elfcpp::SHT_STRTAB) + { + this->error(_("symbol table name section has wrong type: %u"), + static_cast(strtabshdr.get_sh_type())); + return; + } + + // Read the symbol names. + File_view* fvstrtab = this->get_lasting_view(strtabshdr.get_sh_offset(), + strtabshdr.get_sh_size(), + false, true); + + sd->symbols = fvsymtab; + sd->symbols_size = readsize; + sd->external_symbols_offset = need_local_symbols ? locsize : 0; + sd->symbol_names = fvstrtab; + sd->symbol_names_size = + convert_to_section_size_type(strtabshdr.get_sh_size()); +} + +// Return the section index of symbol SYM. Set *VALUE to its value in +// the object file. Set *IS_ORDINARY if this is an ordinary section +// index, not a special code between SHN_LORESERVE and SHN_HIRESERVE. +// Note that for a symbol which is not defined in this object file, +// this will set *VALUE to 0 and return SHN_UNDEF; it will not return +// the final value of the symbol in the link. + +template +unsigned int +Sized_relobj_file::symbol_section_and_value(unsigned int sym, + Address* value, + bool* is_ordinary) +{ + section_size_type symbols_size; + const unsigned char* symbols = this->section_contents(this->symtab_shndx_, + &symbols_size, + false); + + const size_t count = symbols_size / This::sym_size; + gold_assert(sym < count); + + elfcpp::Sym elfsym(symbols + sym * This::sym_size); + *value = elfsym.get_st_value(); + + return this->adjust_sym_shndx(sym, elfsym.get_st_shndx(), is_ordinary); +} + +// Return whether to include a section group in the link. LAYOUT is +// used to keep track of which section groups we have already seen. +// INDEX is the index of the section group and SHDR is the section +// header. If we do not want to include this group, we set bits in +// OMIT for each section which should be discarded. + +template +bool +Sized_relobj_file::include_section_group( + Symbol_table* symtab, + Layout* layout, + unsigned int index, + const char* name, + const unsigned char* shdrs, + const char* section_names, + section_size_type section_names_size, + std::vector* omit) +{ + // Read the section contents. + typename This::Shdr shdr(shdrs + index * This::shdr_size); + const unsigned char* pcon = this->get_view(shdr.get_sh_offset(), + shdr.get_sh_size(), true, false); + const elfcpp::Elf_Word* pword = + reinterpret_cast(pcon); + + // The first word contains flags. We only care about COMDAT section + // groups. Other section groups are always included in the link + // just like ordinary sections. + elfcpp::Elf_Word flags = elfcpp::Swap<32, big_endian>::readval(pword); + + // Look up the group signature, which is the name of a symbol. ELF + // uses a symbol name because some group signatures are long, and + // the name is generally already in the symbol table, so it makes + // sense to put the long string just once in .strtab rather than in + // both .strtab and .shstrtab. + + // Get the appropriate symbol table header (this will normally be + // the single SHT_SYMTAB section, but in principle it need not be). + const unsigned int link = this->adjust_shndx(shdr.get_sh_link()); + typename This::Shdr symshdr(this, this->elf_file_.section_header(link)); + + // Read the symbol table entry. + unsigned int symndx = shdr.get_sh_info(); + if (symndx >= symshdr.get_sh_size() / This::sym_size) + { + this->error(_("section group %u info %u out of range"), + index, symndx); + return false; + } + off_t symoff = symshdr.get_sh_offset() + symndx * This::sym_size; + const unsigned char* psym = this->get_view(symoff, This::sym_size, true, + false); + elfcpp::Sym sym(psym); + + // Read the symbol table names. + section_size_type symnamelen; + const unsigned char* psymnamesu; + psymnamesu = this->section_contents(this->adjust_shndx(symshdr.get_sh_link()), + &symnamelen, true); + const char* psymnames = reinterpret_cast(psymnamesu); + + // Get the section group signature. + if (sym.get_st_name() >= symnamelen) + { + this->error(_("symbol %u name offset %u out of range"), + symndx, sym.get_st_name()); + return false; + } + + std::string signature(psymnames + sym.get_st_name()); + + // It seems that some versions of gas will create a section group + // associated with a section symbol, and then fail to give a name to + // the section symbol. In such a case, use the name of the section. + if (signature[0] == '\0' && sym.get_st_type() == elfcpp::STT_SECTION) + { + bool is_ordinary; + unsigned int sym_shndx = this->adjust_sym_shndx(symndx, + sym.get_st_shndx(), + &is_ordinary); + if (!is_ordinary || sym_shndx >= this->shnum()) + { + this->error(_("symbol %u invalid section index %u"), + symndx, sym_shndx); + return false; + } + 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(); + } + + // Record this section group in the layout, and see whether we've already + // seen one with the same signature. + bool include_group; + bool is_comdat; + Kept_section* kept_section = NULL; + + if ((flags & elfcpp::GRP_COMDAT) == 0) + { + include_group = true; + is_comdat = false; + } + else + { + include_group = layout->find_or_add_kept_section(signature, + this, index, true, + true, &kept_section); + is_comdat = true; + } + + if (is_comdat && include_group) + { + Incremental_inputs* incremental_inputs = layout->incremental_inputs(); + if (incremental_inputs != NULL) + incremental_inputs->report_comdat_group(this, signature.c_str()); + } + + size_t count = shdr.get_sh_size() / sizeof(elfcpp::Elf_Word); + + std::vector shndxes; + bool relocate_group = include_group && parameters->options().relocatable(); + if (relocate_group) + shndxes.reserve(count - 1); + + for (size_t i = 1; i < count; ++i) + { + elfcpp::Elf_Word shndx = + this->adjust_shndx(elfcpp::Swap<32, big_endian>::readval(pword + i)); + + if (relocate_group) + shndxes.push_back(shndx); + + if (shndx >= this->shnum()) + { + this->error(_("section %u in section group %u out of range"), + shndx, index); + continue; + } + + // 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); + + // 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; + } + std::string mname(section_names + member_shdr.get_sh_name()); + + if (include_group) + { + if (is_comdat) + kept_section->add_comdat_section(mname, shndx, + member_shdr.get_sh_size()); + } + else + { + (*omit)[shndx] = true; + + if (is_comdat) + { + Relobj* kept_object = kept_section->object(); + if (kept_section->is_comdat()) + { + // Find the corresponding kept section, and store + // that info in the discarded section table. + unsigned int kept_shndx; + uint64_t kept_size; + if (kept_section->find_comdat_section(mname, &kept_shndx, + &kept_size)) + { + // We don't keep a mapping for this section if + // it has a different size. The mapping is only + // used for relocation processing, and we don't + // want to treat the sections as similar if the + // sizes are different. Checking the section + // size is the approach used by the GNU linker. + if (kept_size == member_shdr.get_sh_size()) + this->set_kept_comdat_section(shndx, kept_object, + kept_shndx); + } + } + else + { + // The existing section is a linkonce section. Add + // a mapping if there is exactly one section in the + // group (which is true when COUNT == 2) and if it + // is the same size. + if (count == 2 + && (kept_section->linkonce_size() + == member_shdr.get_sh_size())) + this->set_kept_comdat_section(shndx, kept_object, + kept_section->shndx()); + } + } + } + } + + if (relocate_group) + layout->layout_group(symtab, this, index, name, signature.c_str(), + shdr, flags, &shndxes); + + return include_group; +} + +// Whether to include a linkonce section in the link. NAME is the +// name of the section and SHDR is the section header. + +// Linkonce sections are a GNU extension implemented in the original +// GNU linker before section groups were defined. The semantics are +// that we only include one linkonce section with a given name. The +// name of a linkonce section is normally .gnu.linkonce.T.SYMNAME, +// where T is the type of section and SYMNAME is the name of a symbol. +// In an attempt to make linkonce sections interact well with section +// groups, we try to identify SYMNAME and use it like a section group +// signature. We want to block section groups with that signature, +// but not other linkonce sections with that signature. We also use +// the full name of the linkonce section as a normal section group +// signature. + +template +bool +Sized_relobj_file::include_linkonce_section( + Layout* layout, + unsigned int index, + const char* name, + const elfcpp::Shdr& shdr) +{ + typename elfcpp::Elf_types::Elf_WXword sh_size = shdr.get_sh_size(); + // In general the symbol name we want will be the string following + // the last '.'. However, we have to handle the case of + // .gnu.linkonce.t.__i686.get_pc_thunk.bx, which was generated by + // some versions of gcc. So we use a heuristic: if the name starts + // with ".gnu.linkonce.t.", we use everything after that. Otherwise + // we look for the last '.'. We can't always simply skip + // ".gnu.linkonce.X", because we have to deal with cases like + // ".gnu.linkonce.d.rel.ro.local". + const char* const linkonce_t = ".gnu.linkonce.t."; + const char* symname; + if (strncmp(name, linkonce_t, strlen(linkonce_t)) == 0) + symname = name + strlen(linkonce_t); + else + symname = strrchr(name, '.') + 1; + std::string sig1(symname); + std::string sig2(name); + Kept_section* kept1; + Kept_section* kept2; + bool include1 = layout->find_or_add_kept_section(sig1, this, index, false, + false, &kept1); + bool include2 = layout->find_or_add_kept_section(sig2, this, index, false, + true, &kept2); + + if (!include2) + { + // We are not including this section because we already saw the + // name of the section as a signature. This normally implies + // that the kept section is another linkonce section. If it is + // the same size, record it as the section which corresponds to + // this one. + if (kept2->object() != NULL + && !kept2->is_comdat() + && kept2->linkonce_size() == sh_size) + this->set_kept_comdat_section(index, kept2->object(), kept2->shndx()); + } + else if (!include1) + { + // The section is being discarded on the basis of its symbol + // name. This means that the corresponding kept section was + // part of a comdat group, and it will be difficult to identify + // the specific section within that group that corresponds to + // this linkonce section. We'll handle the simple case where + // the group has only one member section. Otherwise, it's not + // worth the effort. + unsigned int kept_shndx; + uint64_t kept_size; + if (kept1->object() != NULL + && kept1->is_comdat() + && kept1->find_single_comdat_section(&kept_shndx, &kept_size) + && kept_size == sh_size) + this->set_kept_comdat_section(index, kept1->object(), kept_shndx); + } + else + { + kept1->set_linkonce_size(sh_size); + kept2->set_linkonce_size(sh_size); + } + + return include1 && include2; +} + +// Layout an input section. + +template +inline void +Sized_relobj_file::layout_section( + Layout* layout, + unsigned int shndx, + const char* name, + const typename This::Shdr& shdr, + unsigned int reloc_shndx, + unsigned int reloc_type) +{ + off_t offset; + Output_section* os = layout->layout(this, shndx, name, shdr, + reloc_shndx, reloc_type, &offset); + + this->output_sections()[shndx] = os; + if (offset == -1) + this->section_offsets()[shndx] = invalid_address; + else + this->section_offsets()[shndx] = convert_types(offset); + + // If this section requires special handling, and if there are + // relocs that apply to it, then we must do the special handling + // before we apply the relocs. + if (offset == -1 && reloc_shndx != 0) + this->set_relocs_must_follow_section_writes(); +} + +// Layout an input .eh_frame section. + +template +void +Sized_relobj_file::layout_eh_frame_section( + Layout* layout, + const unsigned char* symbols_data, + section_size_type symbols_size, + const unsigned char* symbol_names_data, + section_size_type symbol_names_size, + unsigned int shndx, + const typename This::Shdr& shdr, + unsigned int reloc_shndx, + unsigned int reloc_type) +{ + gold_assert(this->has_eh_frame_); + + off_t offset; + Output_section* os = layout->layout_eh_frame(this, + symbols_data, + symbols_size, + symbol_names_data, + symbol_names_size, + shndx, + shdr, + reloc_shndx, + reloc_type, + &offset); + this->output_sections()[shndx] = os; + if (os == NULL || offset == -1) + { + // An object can contain at most one section holding exception + // frame information. + gold_assert(this->discarded_eh_frame_shndx_ == -1U); + this->discarded_eh_frame_shndx_ = shndx; + this->section_offsets()[shndx] = invalid_address; + } + else + this->section_offsets()[shndx] = convert_types(offset); + + // If this section requires special handling, and if there are + // relocs that aply to it, then we must do the special handling + // before we apply the relocs. + if (os != NULL && offset == -1 && reloc_shndx != 0) + this->set_relocs_must_follow_section_writes(); +} + +// 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. +// This function is called twice sometimes, two passes, when mapping +// of input sections to output sections must be delayed. +// This is true for the following : +// * Garbage collection (--gc-sections): Some input sections will be +// discarded and hence the assignment must wait until the second pass. +// In the first pass, it is for setting up some sections as roots to +// a work-list for --gc-sections and to do comdat processing. +// * Identical Code Folding (--icf=): Some input sections +// will be folded and hence the assignment must wait. +// * Using plugins to map some sections to unique segments: Mapping +// some sections to unique segments requires mapping them to unique +// output sections too. This can be done via plugins now and this +// information is not available in the first pass. + +template +void +Sized_relobj_file::do_layout(Symbol_table* symtab, + Layout* layout, + Read_symbols_data* sd) +{ + const unsigned int shnum = this->shnum(); + + /* Should this function be called twice? */ + bool is_two_pass = (parameters->options().gc_sections() + || parameters->options().icf_enabled() + || layout->is_unique_segment_for_sections_specified()); + + /* Only one of is_pass_one and is_pass_two is true. Both are false when + a two-pass approach is not needed. */ + bool is_pass_one = false; + bool is_pass_two = false; + + Symbols_data* gc_sd = NULL; + + /* Check if do_layout needs to be two-pass. If so, find out which pass + should happen. In the first pass, the data in sd is saved to be used + later in the second pass. */ + if (is_two_pass) + { + gc_sd = this->get_symbols_data(); + if (gc_sd == NULL) + { + gold_assert(sd != NULL); + is_pass_one = true; + } + else + { + if (parameters->options().gc_sections()) + gold_assert(symtab->gc()->is_worklist_ready()); + if (parameters->options().icf_enabled()) + gold_assert(symtab->icf()->is_icf_ready()); + is_pass_two = true; + } + } + + if (shnum == 0) + return; + + if (is_pass_one) + { + // 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); + } + + const unsigned char* section_headers_data = NULL; + section_size_type section_names_size; + const unsigned char* symbols_data = NULL; + section_size_type symbols_size; + const unsigned char* symbol_names_data = NULL; + section_size_type symbol_names_size; + + if (is_two_pass) + { + section_headers_data = gc_sd->section_headers_data; + section_names_size = gc_sd->section_names_size; + symbols_data = gc_sd->symbols_data; + symbols_size = gc_sd->symbols_size; + symbol_names_data = gc_sd->symbol_names_data; + symbol_names_size = gc_sd->symbol_names_size; + } + else + { + section_headers_data = sd->section_headers->data(); + section_names_size = sd->section_names_size; + if (sd->symbols != NULL) + symbols_data = sd->symbols->data(); + symbols_size = sd->symbols_size; + if (sd->symbol_names != NULL) + symbol_names_data = sd->symbol_names->data(); + symbol_names_size = sd->symbol_names_size; + } + + // Get the section headers. + const unsigned char* shdrs = section_headers_data; + const unsigned char* pshdrs; + + // Get the section names. + const unsigned char* pnamesu = (is_two_pass + ? gc_sd->section_names_data + : sd->section_names->data()); + + const char* pnames = reinterpret_cast(pnamesu); + + // If any input files have been claimed by plugins, we need to defer + // actual layout until the replacement files have arrived. + const bool should_defer_layout = + (parameters->options().has_plugins() + && parameters->options().plugins()->should_defer_layout()); + unsigned int num_sections_to_defer = 0; + + // For each section, record the index of the reloc section if any. + // Use 0 to mean that there is no reloc section, -1U to mean that + // there is more than one. + std::vector reloc_shndx(shnum, 0); + std::vector reloc_type(shnum, elfcpp::SHT_NULL); + // Skip the first, dummy, section. + pshdrs = shdrs + This::shdr_size; + for (unsigned int i = 1; i < shnum; ++i, pshdrs += This::shdr_size) + { + typename This::Shdr shdr(pshdrs); + + // 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; + + unsigned int sh_type = shdr.get_sh_type(); + if (sh_type == elfcpp::SHT_REL || sh_type == elfcpp::SHT_RELA) + { + unsigned int target_shndx = this->adjust_shndx(shdr.get_sh_info()); + if (target_shndx == 0 || target_shndx >= shnum) + { + this->error(_("relocation section %u has bad info %u"), + i, target_shndx); + continue; + } + + if (reloc_shndx[target_shndx] != 0) + reloc_shndx[target_shndx] = -1U; + else + { + reloc_shndx[target_shndx] = i; + reloc_type[target_shndx] = sh_type; + } + } + } + + Output_sections& out_sections(this->output_sections()); + std::vector
& out_section_offsets(this->section_offsets()); + + if (!is_pass_two) + { + out_sections.resize(shnum); + out_section_offsets.resize(shnum); + } + + // If we are only linking for symbols, then there is nothing else to + // do here. + if (this->input_file()->just_symbols()) + { + if (!is_pass_two) + { + delete sd->section_headers; + sd->section_headers = NULL; + delete sd->section_names; + sd->section_names = NULL; + } + return; + } + + if (num_sections_to_defer > 0) + { + parameters->options().plugins()->add_deferred_layout_object(this); + this->deferred_layout_.reserve(num_sections_to_defer); + } + + // Whether we've seen a .note.GNU-stack section. + bool seen_gnu_stack = false; + // The flags of a .note.GNU-stack section. + uint64_t gnu_stack_flags = 0; + + // Keep track of which sections to omit. + std::vector omit(shnum, false); + + // Keep track of reloc sections when emitting relocations. + const bool relocatable = parameters->options().relocatable(); + const bool emit_relocs = (relocatable + || parameters->options().emit_relocs()); + std::vector reloc_sections; + + // Keep track of .eh_frame sections. + std::vector eh_frame_sections; + + // Keep track of .debug_info and .debug_types sections. + std::vector debug_info_sections; + std::vector debug_types_sections; + + // Skip the first, dummy, section. + pshdrs = shdrs + This::shdr_size; + for (unsigned int i = 1; i < shnum; ++i, pshdrs += This::shdr_size) + { + typename This::Shdr shdr(pshdrs); + + if (shdr.get_sh_name() >= section_names_size) + { + this->error(_("bad section name offset for section %u: %lu"), + i, static_cast(shdr.get_sh_name())); + return; + } + + const char* name = pnames + shdr.get_sh_name(); + + if (!is_pass_two) + { + 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) + { + 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 + // -fsplit-stack. + if (this->handle_split_stack_section(name)) + { + if (!relocatable && !parameters->options().shared()) + omit[i] = true; + } + + // Skip attributes section. + if (parameters->target().is_attributes_section(name)) + { + omit[i] = true; + } + + 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)) + discard = true; + } + else if ((shdr.get_sh_flags() & elfcpp::SHF_GROUP) == 0 + && Layout::is_linkonce(name)) + { + if (!this->include_linkonce_section(layout, i, name, shdr)) + discard = true; + } + } + + // Add the section to the incremental inputs layout. + Incremental_inputs* incremental_inputs = layout->incremental_inputs(); + if (incremental_inputs != NULL + && !discard + && can_incremental_update(shdr.get_sh_type())) + { + off_t sh_size = shdr.get_sh_size(); + section_size_type uncompressed_size; + if (this->section_is_compressed(i, &uncompressed_size)) + sh_size = uncompressed_size; + incremental_inputs->report_input_section(this, i, name, sh_size); + } + + if (discard) + { + // Do not include this section in the link. + out_sections[i] = NULL; + out_section_offsets[i] = invalid_address; + continue; + } + } + + if (is_pass_one && parameters->options().gc_sections()) + { + if (this->is_section_name_included(name) + || layout->keep_input_section (this, 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 + // ones associated with sections which are not being discarded. + // However, we don't know that yet for all sections. So save + // reloc sections and process them later. Garbage collection is + // not triggered when relocatable code is desired. + if (emit_relocs + && (shdr.get_sh_type() == elfcpp::SHT_REL + || shdr.get_sh_type() == elfcpp::SHT_RELA)) + { + reloc_sections.push_back(i); + continue; + } + + if (relocatable && shdr.get_sh_type() == elfcpp::SHT_GROUP) + continue; + + // The .eh_frame section is special. It holds exception frame + // information that we need to read in order to generate the + // exception frame header. We process these after all the other + // sections so that the exception frame reader can reliably + // 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_pass_one) + { + out_sections[i] = reinterpret_cast(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; + } + + if (is_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; + } + } + + if (is_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(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_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(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_pass_two + && (out_sections[i] == reinterpret_cast(2))) + continue; + + if (is_pass_one) + { + // This is during garbage collection. The out_sections are + // assigned in the second call to this function. + out_sections[i] = reinterpret_cast(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 generating a .gdb_index section, we do additional + // processing of .debug_info and .debug_types sections after all + // the other sections for the same reason as above. + if (!relocatable + && parameters->options().gdb_index() + && !(shdr.get_sh_flags() & elfcpp::SHF_ALLOC)) + { + if (strcmp(name, ".debug_info") == 0 + || strcmp(name, ".zdebug_info") == 0) + debug_info_sections.push_back(i); + else if (strcmp(name, ".debug_types") == 0 + || strcmp(name, ".zdebug_types") == 0) + debug_types_sections.push_back(i); + } + } + } + + if (!is_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. + if (emit_relocs) + this->size_relocatable_relocs(); + + gold_assert(!is_two_pass || reloc_sections.empty()); + + for (std::vector::const_iterator p = reloc_sections.begin(); + p != reloc_sections.end(); + ++p) + { + unsigned int i = *p; + const unsigned char* pshdr; + pshdr = section_headers_data + i * This::shdr_size; + typename This::Shdr shdr(pshdr); + + unsigned int data_shndx = this->adjust_shndx(shdr.get_sh_info()); + if (data_shndx >= shnum) + { + // We already warned about this above. + continue; + } + + Output_section* data_section = out_sections[data_shndx]; + if (data_section == reinterpret_cast(2)) + { + // 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)); + out_sections[i] = reinterpret_cast(2); + out_section_offsets[i] = invalid_address; + continue; + } + if (data_section == NULL) + { + out_sections[i] = NULL; + out_section_offsets[i] = invalid_address; + continue; + } + + Relocatable_relocs* rr = new Relocatable_relocs(); + this->set_relocatable_relocs(i, rr); + + Output_section* os = layout->layout_reloc(this, i, shdr, data_section, + rr); + out_sections[i] = os; + out_section_offsets[i] = invalid_address; + } + + // Handle the .eh_frame sections at the end. + gold_assert(!is_pass_one || eh_frame_sections.empty()); + for (std::vector::const_iterator p = eh_frame_sections.begin(); + p != eh_frame_sections.end(); + ++p) + { + unsigned int i = *p; + const unsigned char* pshdr; + pshdr = section_headers_data + i * This::shdr_size; + typename This::Shdr shdr(pshdr); + + this->layout_eh_frame_section(layout, + symbols_data, + symbols_size, + symbol_names_data, + symbol_names_size, + i, + shdr, + reloc_shndx[i], + reloc_type[i]); + } + + // When building a .gdb_index section, scan the .debug_info and + // .debug_types sections. + gold_assert(!is_pass_one + || (debug_info_sections.empty() && debug_types_sections.empty())); + for (std::vector::const_iterator p + = debug_info_sections.begin(); + p != debug_info_sections.end(); + ++p) + { + unsigned int i = *p; + layout->add_to_gdb_index(false, this, symbols_data, symbols_size, + i, reloc_shndx[i], reloc_type[i]); + } + for (std::vector::const_iterator p + = debug_types_sections.begin(); + p != debug_types_sections.end(); + ++p) + { + unsigned int i = *p; + layout->add_to_gdb_index(true, this, symbols_data, symbols_size, + i, reloc_shndx[i], reloc_type[i]); + } + + if (is_pass_two) + { + delete[] gc_sd->section_headers_data; + delete[] gc_sd->section_names_data; + delete[] gc_sd->symbols_data; + delete[] gc_sd->symbol_names_data; + this->set_symbols_data(NULL); + } + else + { + delete sd->section_headers; + sd->section_headers = NULL; + delete sd->section_names; + sd->section_names = NULL; + } +} + +// Layout sections whose layout was deferred while waiting for +// input files from a plugin. + +template +void +Sized_relobj_file::do_layout_deferred_sections(Layout* layout) +{ + typename std::vector::iterator deferred; + + for (deferred = this->deferred_layout_.begin(); + deferred != this->deferred_layout_.end(); + ++deferred) + { + typename This::Shdr shdr(deferred->shdr_data_); + + if (!parameters->options().relocatable() + && deferred->name_ == ".eh_frame" + && this->check_eh_frame_flags(&shdr)) + { + // Checking is_section_included is not reliable for + // .eh_frame sections, because they do not have an output + // section. This is not a problem normally because we call + // layout_eh_frame_section unconditionally, but when + // deferring sections that is not true. We don't want to + // keep all .eh_frame sections because that will cause us to + // keep all sections that they refer to, which is the wrong + // way around. Instead, the eh_frame code will discard + // .eh_frame sections that refer to discarded sections. + + // Reading the symbols again here may be slow. + Read_symbols_data sd; + this->read_symbols(&sd); + this->layout_eh_frame_section(layout, + sd.symbols->data(), + sd.symbols_size, + sd.symbol_names->data(), + sd.symbol_names_size, + deferred->shndx_, + shdr, + deferred->reloc_shndx_, + deferred->reloc_type_); + continue; + } + + // If the section is not included, it is because the garbage collector + // decided it is not needed. Avoid reverting that decision. + if (!this->is_section_included(deferred->shndx_)) + continue; + + this->layout_section(layout, deferred->shndx_, deferred->name_.c_str(), + shdr, deferred->reloc_shndx_, + deferred->reloc_type_); + } + + this->deferred_layout_.clear(); + + // Now handle the deferred relocation sections. + + Output_sections& out_sections(this->output_sections()); + std::vector
& out_section_offsets(this->section_offsets()); + + for (deferred = this->deferred_layout_relocs_.begin(); + deferred != this->deferred_layout_relocs_.end(); + ++deferred) + { + unsigned int shndx = deferred->shndx_; + typename This::Shdr shdr(deferred->shdr_data_); + unsigned int data_shndx = this->adjust_shndx(shdr.get_sh_info()); + + Output_section* data_section = out_sections[data_shndx]; + if (data_section == NULL) + { + out_sections[shndx] = NULL; + out_section_offsets[shndx] = invalid_address; + continue; + } + + Relocatable_relocs* rr = new Relocatable_relocs(); + this->set_relocatable_relocs(shndx, rr); + + Output_section* os = layout->layout_reloc(this, shndx, shdr, + data_section, rr); + out_sections[shndx] = os; + out_section_offsets[shndx] = invalid_address; + } +} + +// Add the symbols to the symbol table. + +template +void +Sized_relobj_file::do_add_symbols(Symbol_table* symtab, + Read_symbols_data* sd, + Layout*) +{ + if (sd->symbols == NULL) + { + gold_assert(sd->symbol_names == NULL); + return; + } + + const int sym_size = This::sym_size; + size_t symcount = ((sd->symbols_size - sd->external_symbols_offset) + / sym_size); + if (symcount * sym_size != sd->symbols_size - sd->external_symbols_offset) + { + this->error(_("size of symbols is not multiple of symbol size")); + return; + } + + this->symbols_.resize(symcount); + + const char* sym_names = + reinterpret_cast(sd->symbol_names->data()); + symtab->add_from_relobj(this, + sd->symbols->data() + sd->external_symbols_offset, + symcount, this->local_symbol_count_, + sym_names, sd->symbol_names_size, + &this->symbols_, + &this->defined_count_); + + delete sd->symbols; + sd->symbols = NULL; + delete sd->symbol_names; + sd->symbol_names = NULL; +} + +// Find out if this object, that is a member of a lib group, should be included +// in the link. We check every symbol defined by this object. If the symbol +// table has a strong undefined reference to that symbol, we have to include +// the object. + +template +Archive::Should_include +Sized_relobj_file::do_should_include_member( + Symbol_table* symtab, + Layout* layout, + Read_symbols_data* sd, + std::string* why) +{ + char* tmpbuf = NULL; + size_t tmpbuflen = 0; + const char* sym_names = + reinterpret_cast(sd->symbol_names->data()); + const unsigned char* syms = + sd->symbols->data() + sd->external_symbols_offset; + const int sym_size = elfcpp::Elf_sizes::sym_size; + size_t symcount = ((sd->symbols_size - sd->external_symbols_offset) + / sym_size); + + const unsigned char* p = syms; + + for (size_t i = 0; i < symcount; ++i, p += sym_size) + { + elfcpp::Sym sym(p); + unsigned int st_shndx = sym.get_st_shndx(); + if (st_shndx == elfcpp::SHN_UNDEF) + continue; + + unsigned int st_name = sym.get_st_name(); + const char* name = sym_names + st_name; + Symbol* symbol; + Archive::Should_include t = Archive::should_include_member(symtab, + layout, + name, + &symbol, why, + &tmpbuf, + &tmpbuflen); + if (t == Archive::SHOULD_INCLUDE_YES) + { + if (tmpbuf != NULL) + free(tmpbuf); + return t; + } + } + if (tmpbuf != NULL) + free(tmpbuf); + return Archive::SHOULD_INCLUDE_UNKNOWN; +} + +// Iterate over global defined symbols, calling a visitor class V for each. + +template +void +Sized_relobj_file::do_for_all_global_symbols( + Read_symbols_data* sd, + Library_base::Symbol_visitor_base* v) +{ + const char* sym_names = + reinterpret_cast(sd->symbol_names->data()); + const unsigned char* syms = + sd->symbols->data() + sd->external_symbols_offset; + const int sym_size = elfcpp::Elf_sizes::sym_size; + size_t symcount = ((sd->symbols_size - sd->external_symbols_offset) + / sym_size); + const unsigned char* p = syms; + + for (size_t i = 0; i < symcount; ++i, p += sym_size) + { + elfcpp::Sym sym(p); + if (sym.get_st_shndx() != elfcpp::SHN_UNDEF) + v->visit(sym_names + sym.get_st_name()); + } +} + +// Return whether the local symbol SYMNDX has a PLT offset. + +template +bool +Sized_relobj_file::local_has_plt_offset( + unsigned int symndx) const +{ + typename Local_plt_offsets::const_iterator p = + this->local_plt_offsets_.find(symndx); + return p != this->local_plt_offsets_.end(); +} + +// Get the PLT offset of a local symbol. + +template +unsigned int +Sized_relobj_file::do_local_plt_offset( + unsigned int symndx) const +{ + typename Local_plt_offsets::const_iterator p = + this->local_plt_offsets_.find(symndx); + gold_assert(p != this->local_plt_offsets_.end()); + return p->second; +} + +// Set the PLT offset of a local symbol. + +template +void +Sized_relobj_file::set_local_plt_offset( + unsigned int symndx, unsigned int plt_offset) +{ + std::pair ins = + this->local_plt_offsets_.insert(std::make_pair(symndx, plt_offset)); + gold_assert(ins.second); +} + +// First pass over the local symbols. Here we add their names to +// *POOL and *DYNPOOL, and we store the symbol value in +// THIS->LOCAL_VALUES_. This function is always called from a +// singleton thread. This is followed by a call to +// finalize_local_symbols. + +template +void +Sized_relobj_file::do_count_local_symbols(Stringpool* pool, + Stringpool* dynpool) +{ + gold_assert(this->symtab_shndx_ != -1U); + if (this->symtab_shndx_ == 0) + { + // This object has no symbols. Weird but legal. + return; + } + + // Read the symbol table section header. + const unsigned int symtab_shndx = this->symtab_shndx_; + typename This::Shdr symtabshdr(this, + this->elf_file_.section_header(symtab_shndx)); + gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB); + + // Read the local symbols. + const int sym_size = This::sym_size; + const unsigned int loccount = this->local_symbol_count_; + gold_assert(loccount == symtabshdr.get_sh_info()); + off_t locsize = loccount * sym_size; + const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(), + locsize, true, true); + + // Read the symbol names. + const unsigned int strtab_shndx = + this->adjust_shndx(symtabshdr.get_sh_link()); + section_size_type strtab_size; + const unsigned char* pnamesu = this->section_contents(strtab_shndx, + &strtab_size, + true); + const char* pnames = reinterpret_cast(pnamesu); + + // Loop over the local symbols. + + const Output_sections& out_sections(this->output_sections()); + unsigned int shnum = this->shnum(); + unsigned int count = 0; + unsigned int dyncount = 0; + // Skip the first, dummy, symbol. + psyms += sym_size; + bool strip_all = parameters->options().strip_all(); + bool discard_all = parameters->options().discard_all(); + bool discard_locals = parameters->options().discard_locals(); + for (unsigned int i = 1; i < loccount; ++i, psyms += sym_size) + { + elfcpp::Sym sym(psyms); + + Symbol_value& lv(this->local_values_[i]); + + bool is_ordinary; + unsigned int shndx = this->adjust_sym_shndx(i, sym.get_st_shndx(), + &is_ordinary); + lv.set_input_shndx(shndx, is_ordinary); + + if (sym.get_st_type() == elfcpp::STT_SECTION) + lv.set_is_section_symbol(); + else if (sym.get_st_type() == elfcpp::STT_TLS) + lv.set_is_tls_symbol(); + else if (sym.get_st_type() == elfcpp::STT_GNU_IFUNC) + lv.set_is_ifunc_symbol(); + + // Save the input symbol value for use in do_finalize_local_symbols(). + lv.set_input_value(sym.get_st_value()); + + // Decide whether this symbol should go into the output file. + + 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; + } + + if (sym.get_st_type() == elfcpp::STT_SECTION + || !this->adjust_local_symbol(&lv)) + { + lv.set_no_output_symtab_entry(); + gold_assert(!lv.needs_output_dynsym_entry()); + continue; + } + + if (sym.get_st_name() >= strtab_size) + { + this->error(_("local symbol %u section name out of range: %u >= %u"), + i, sym.get_st_name(), + static_cast(strtab_size)); + lv.set_no_output_symtab_entry(); + continue; + } + + const char* name = pnames + sym.get_st_name(); + + // If needed, add the symbol to the dynamic symbol table string pool. + if (lv.needs_output_dynsym_entry()) + { + dynpool->add(name, true, NULL); + ++dyncount; + } + + if (strip_all + || (discard_all && lv.may_be_discarded_from_output_symtab())) + { + lv.set_no_output_symtab_entry(); + continue; + } + + // If --discard-locals option is used, discard all temporary local + // symbols. These symbols start with system-specific local label + // prefixes, typically .L for ELF system. We want to be compatible + // with GNU ld so here we essentially use the same check in + // bfd_is_local_label(). The code is different because we already + // know that: + // + // - the symbol is local and thus cannot have global or weak binding. + // - the symbol is not a section symbol. + // - the symbol has a name. + // + // We do not discard a symbol if it needs a dynamic symbol entry. + if (discard_locals + && sym.get_st_type() != elfcpp::STT_FILE + && !lv.needs_output_dynsym_entry() + && lv.may_be_discarded_from_output_symtab() + && parameters->target().is_local_label_name(name)) + { + lv.set_no_output_symtab_entry(); + continue; + } + + // 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; + } + + // Add the symbol to the symbol table string pool. + pool->add(name, true, NULL); + ++count; + } + + this->output_local_symbol_count_ = count; + this->output_local_dynsym_count_ = dyncount; +} + +// Compute the final value of a local symbol. + +template +typename Sized_relobj_file::Compute_final_local_value_status +Sized_relobj_file::compute_final_local_value_internal( + unsigned int r_sym, + const Symbol_value* lv_in, + Symbol_value* lv_out, + bool relocatable, + const Output_sections& out_sections, + const std::vector
& out_offsets, + const Symbol_table* symtab) +{ + // We are going to overwrite *LV_OUT, if it has a merged symbol value, + // we may have a memory leak. + gold_assert(lv_out->has_output_value()); + + bool is_ordinary; + unsigned int shndx = lv_in->input_shndx(&is_ordinary); + + // Set the output symbol value. + + if (!is_ordinary) + { + if (shndx == elfcpp::SHN_ABS || Symbol::is_common_shndx(shndx)) + lv_out->set_output_value(lv_in->input_value()); + else + { + this->error(_("unknown section index %u for local symbol %u"), + shndx, r_sym); + lv_out->set_output_value(0); + return This::CFLV_ERROR; + } + } + else + { + if (shndx >= this->shnum()) + { + this->error(_("local symbol %u section index %u out of range"), + r_sym, shndx); + lv_out->set_output_value(0); + return This::CFLV_ERROR; + } + + Output_section* os = out_sections[shndx]; + Address secoffset = out_offsets[shndx]; + if (symtab->is_section_folded(this, shndx)) + { + gold_assert(os == NULL && secoffset == invalid_address); + // Get the os of the section it is folded onto. + Section_id folded = symtab->icf()->get_folded_section(this, + shndx); + gold_assert(folded.first != NULL); + Sized_relobj_file* folded_obj = reinterpret_cast + *>(folded.first); + 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) + { + const Output_relaxed_input_section* relaxed_section = + os->find_relaxed_input_section(folded_obj, folded.second); + gold_assert(relaxed_section != NULL); + secoffset = relaxed_section->address() - os->address(); + } + } + + if (os == NULL) + { + // This local symbol belongs to a section we are discarding. + // In some cases when applying relocations later, we will + // attempt to match it to the corresponding kept section, + // so we leave the input value unchanged here. + return This::CFLV_DISCARDED; + } + 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_) + { + // This local symbol belongs to a discarded .eh_frame + // section. Just treat it like the case in which + // os == NULL above. + gold_assert(this->has_eh_frame_); + return This::CFLV_DISCARDED; + } + else if (!lv_in->is_section_symbol()) + { + // This is not a section symbol. We can determine + // the final value now. + lv_out->set_output_value( + os->output_address(this, shndx, lv_in->input_value())); + } + else if (!os->find_starting_output_address(this, shndx, &start)) + { + // This is a section symbol, but apparently not one in a + // merged section. First check to see if this is a relaxed + // input section. If so, use its address. Otherwise just + // use the start of the output section. This happens with + // relocatable links when the input object has section + // symbols for arbitrary non-merge sections. + const Output_section_data* posd = + os->find_relaxed_input_section(this, shndx); + if (posd != NULL) + { + Address relocatable_link_adjustment = + relocatable ? os->address() : 0; + lv_out->set_output_value(posd->address() + - relocatable_link_adjustment); + } + else + lv_out->set_output_value(os->address()); + } + else + { + // We have to consider the addend to determine the + // value to use in a relocation. START is the start + // of this input section. If we are doing a relocatable + // link, use offset from start output section instead of + // address. + Address adjusted_start = + relocatable ? start - os->address() : start; + Merged_symbol_value* msv = + new Merged_symbol_value(lv_in->input_value(), + adjusted_start); + lv_out->set_merged_symbol_value(msv); + } + } + else if (lv_in->is_tls_symbol()) + lv_out->set_output_value(os->tls_offset() + + secoffset + + lv_in->input_value()); + else + lv_out->set_output_value((relocatable ? 0 : os->address()) + + secoffset + + lv_in->input_value()); + } + return This::CFLV_OK; +} + +// Compute final local symbol value. R_SYM is the index of a local +// symbol in symbol table. LV points to a symbol value, which is +// expected to hold the input value and to be over-written by the +// final value. SYMTAB points to a symbol table. Some targets may want +// to know would-be-finalized local symbol values in relaxation. +// Hence we provide this method. Since this method updates *LV, a +// callee should make a copy of the original local symbol value and +// use the copy instead of modifying an object's local symbols before +// everything is finalized. The caller should also free up any allocated +// memory in the return value in *LV. +template +typename Sized_relobj_file::Compute_final_local_value_status +Sized_relobj_file::compute_final_local_value( + unsigned int r_sym, + const Symbol_value* lv_in, + Symbol_value* lv_out, + const Symbol_table* symtab) +{ + // This is just a wrapper of compute_final_local_value_internal. + const bool relocatable = parameters->options().relocatable(); + const Output_sections& out_sections(this->output_sections()); + const std::vector
& out_offsets(this->section_offsets()); + return this->compute_final_local_value_internal(r_sym, lv_in, lv_out, + relocatable, out_sections, + out_offsets, symtab); +} + +// Finalize the local symbols. Here we set the final value in +// THIS->LOCAL_VALUES_ and set their output symbol table indexes. +// This function is always called from a singleton thread. The actual +// output of the local symbols will occur in a separate task. + +template +unsigned int +Sized_relobj_file::do_finalize_local_symbols( + unsigned int index, + off_t off, + Symbol_table* symtab) +{ + gold_assert(off == static_cast(align_address(off, size >> 3))); + + const unsigned int loccount = this->local_symbol_count_; + this->local_symbol_offset_ = off; + + const bool relocatable = parameters->options().relocatable(); + const Output_sections& out_sections(this->output_sections()); + const std::vector
& out_offsets(this->section_offsets()); + + for (unsigned int i = 1; i < loccount; ++i) + { + Symbol_value* lv = &this->local_values_[i]; + + Compute_final_local_value_status cflv_status = + this->compute_final_local_value_internal(i, lv, lv, relocatable, + out_sections, out_offsets, + symtab); + switch (cflv_status) + { + case CFLV_OK: + if (!lv->is_output_symtab_index_set()) + { + lv->set_output_symtab_index(index); + ++index; + } + break; + case CFLV_DISCARDED: + case CFLV_ERROR: + // Do nothing. + break; + default: + gold_unreachable(); + } + } + return index; +} + +// Set the output dynamic symbol table indexes for the local variables. + +template +unsigned int +Sized_relobj_file::do_set_local_dynsym_indexes( + unsigned int index) +{ + const unsigned int loccount = this->local_symbol_count_; + for (unsigned int i = 1; i < loccount; ++i) + { + Symbol_value& lv(this->local_values_[i]); + if (lv.needs_output_dynsym_entry()) + { + lv.set_output_dynsym_index(index); + ++index; + } + } + return index; +} + +// Set the offset where local dynamic symbol information will be stored. +// Returns the count of local symbols contributed to the symbol table by +// this object. + +template +unsigned int +Sized_relobj_file::do_set_local_dynsym_offset(off_t off) +{ + gold_assert(off == static_cast(align_address(off, size >> 3))); + this->local_dynsym_offset_ = off; + return this->output_local_dynsym_count_; +} + +// If Symbols_data is not NULL get the section flags from here otherwise +// get it from the file. + +template +uint64_t +Sized_relobj_file::do_section_flags(unsigned int shndx) +{ + Symbols_data* sd = this->get_symbols_data(); + if (sd != NULL) + { + const unsigned char* pshdrs = sd->section_headers_data + + This::shdr_size * shndx; + typename This::Shdr shdr(pshdrs); + return shdr.get_sh_flags(); + } + // If sd is NULL, read the section header from the file. + return this->elf_file_.section_flags(shndx); +} + +// Get the section's ent size from Symbols_data. Called by get_section_contents +// in icf.cc + +template +uint64_t +Sized_relobj_file::do_section_entsize(unsigned int shndx) +{ + Symbols_data* sd = this->get_symbols_data(); + gold_assert(sd != NULL); + + const unsigned char* pshdrs = sd->section_headers_data + + This::shdr_size * shndx; + typename This::Shdr shdr(pshdrs); + return shdr.get_sh_entsize(); +} + +// Write out the local symbols. + +template +void +Sized_relobj_file::write_local_symbols( + Output_file* of, + const Stringpool* sympool, + const Stringpool* dynpool, + Output_symtab_xindex* symtab_xindex, + Output_symtab_xindex* dynsym_xindex, + off_t symtab_off) +{ + const bool strip_all = parameters->options().strip_all(); + if (strip_all) + { + if (this->output_local_dynsym_count_ == 0) + return; + this->output_local_symbol_count_ = 0; + } + + gold_assert(this->symtab_shndx_ != -1U); + if (this->symtab_shndx_ == 0) + { + // This object has no symbols. Weird but legal. + return; + } + + // Read the symbol table section header. + const unsigned int symtab_shndx = this->symtab_shndx_; + typename This::Shdr symtabshdr(this, + this->elf_file_.section_header(symtab_shndx)); + gold_assert(symtabshdr.get_sh_type() == elfcpp::SHT_SYMTAB); + const unsigned int loccount = this->local_symbol_count_; + gold_assert(loccount == symtabshdr.get_sh_info()); + + // Read the local symbols. + const int sym_size = This::sym_size; + off_t locsize = loccount * sym_size; + const unsigned char* psyms = this->get_view(symtabshdr.get_sh_offset(), + locsize, true, false); + + // Read the symbol names. + const unsigned int strtab_shndx = + this->adjust_shndx(symtabshdr.get_sh_link()); + section_size_type strtab_size; + const unsigned char* pnamesu = this->section_contents(strtab_shndx, + &strtab_size, + false); + const char* pnames = reinterpret_cast(pnamesu); + + // Get views into the output file for the portions of the symbol table + // and the dynamic symbol table that we will be writing. + off_t output_size = this->output_local_symbol_count_ * sym_size; + unsigned char* oview = NULL; + if (output_size > 0) + oview = of->get_output_view(symtab_off + this->local_symbol_offset_, + output_size); + + off_t dyn_output_size = this->output_local_dynsym_count_ * sym_size; + unsigned char* dyn_oview = NULL; + if (dyn_output_size > 0) + dyn_oview = of->get_output_view(this->local_dynsym_offset_, + dyn_output_size); + + const Output_sections out_sections(this->output_sections()); + + gold_assert(this->local_values_.size() == loccount); + + unsigned char* ov = oview; + unsigned char* dyn_ov = dyn_oview; + psyms += sym_size; + for (unsigned int i = 1; i < loccount; ++i, psyms += sym_size) + { + elfcpp::Sym isym(psyms); + + Symbol_value& lv(this->local_values_[i]); + + bool is_ordinary; + unsigned int st_shndx = this->adjust_sym_shndx(i, isym.get_st_shndx(), + &is_ordinary); + if (is_ordinary) + { + gold_assert(st_shndx < out_sections.size()); + if (out_sections[st_shndx] == NULL) + continue; + st_shndx = out_sections[st_shndx]->out_shndx(); + if (st_shndx >= elfcpp::SHN_LORESERVE) + { + if (lv.has_output_symtab_entry()) + symtab_xindex->add(lv.output_symtab_index(), st_shndx); + if (lv.has_output_dynsym_entry()) + dynsym_xindex->add(lv.output_dynsym_index(), st_shndx); + st_shndx = elfcpp::SHN_XINDEX; + } + } + + // Write the symbol to the output symbol table. + if (lv.has_output_symtab_entry()) + { + elfcpp::Sym_write 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 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; + } + } + + + if (output_size > 0) + { + gold_assert(ov - oview == output_size); + of->write_output_view(symtab_off + this->local_symbol_offset_, + output_size, oview); + } + + if (dyn_output_size > 0) + { + gold_assert(dyn_ov - dyn_oview == dyn_output_size); + of->write_output_view(this->local_dynsym_offset_, dyn_output_size, + dyn_oview); + } +} + +// Set *INFO to symbolic information about the offset OFFSET in the +// section SHNDX. Return true if we found something, false if we +// found nothing. + +template +bool +Sized_relobj_file::get_symbol_location_info( + unsigned int shndx, + off_t offset, + Symbol_location_info* info) +{ + if (this->symtab_shndx_ == 0) + return false; + + section_size_type symbols_size; + const unsigned char* symbols = this->section_contents(this->symtab_shndx_, + &symbols_size, + false); + + unsigned int symbol_names_shndx = + this->adjust_shndx(this->section_link(this->symtab_shndx_)); + section_size_type names_size; + const unsigned char* symbol_names_u = + this->section_contents(symbol_names_shndx, &names_size, false); + const char* symbol_names = reinterpret_cast(symbol_names_u); + + const int sym_size = This::sym_size; + const size_t count = symbols_size / sym_size; + + const unsigned char* p = symbols; + for (size_t i = 0; i < count; ++i, p += sym_size) + { + elfcpp::Sym sym(p); + + if (sym.get_st_type() == elfcpp::STT_FILE) + { + if (sym.get_st_name() >= names_size) + info->source_file = "(invalid)"; + else + info->source_file = symbol_names + sym.get_st_name(); + continue; + } + + bool is_ordinary; + unsigned int st_shndx = this->adjust_sym_shndx(i, sym.get_st_shndx(), + &is_ordinary); + if (is_ordinary + && st_shndx == shndx + && static_cast(sym.get_st_value()) <= offset + && (static_cast(sym.get_st_value() + sym.get_st_size()) + > offset)) + { + info->enclosing_symbol_type = sym.get_st_type(); + 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); + } + } + } + return true; + } + } + + return false; +} + +// Look for a kept section corresponding to the given discarded section, +// and return its output address. This is used only for relocations in +// debugging sections. If we can't find the kept section, return 0. + +template +typename Sized_relobj_file::Address +Sized_relobj_file::map_to_kept_section( + unsigned int shndx, + bool* found) const +{ + Relobj* kept_object; + unsigned int kept_shndx; + if (this->get_kept_comdat_section(shndx, &kept_object, &kept_shndx)) + { + Sized_relobj_file* kept_relobj = + static_cast*>(kept_object); + Output_section* os = kept_relobj->output_section(kept_shndx); + Address offset = kept_relobj->get_output_section_offset(kept_shndx); + if (os != NULL && offset != invalid_address) + { + *found = true; + return os->address() + offset; + } + } + *found = false; + return 0; +} + +// Get symbol counts. + +template +void +Sized_relobj_file::do_get_global_symbol_counts( + const Symbol_table*, + size_t* defined, + size_t* used) const +{ + *defined = this->defined_count_; + size_t count = 0; + for (typename Symbols::const_iterator p = this->symbols_.begin(); + p != this->symbols_.end(); + ++p) + if (*p != NULL + && (*p)->source() == Symbol::FROM_OBJECT + && (*p)->object() == this + && (*p)->is_defined()) + ++count; + *used = count; +} + +// Return a view of the decompressed contents of a section. Set *PLEN +// to the size. Set *IS_NEW to true if the contents need to be freed +// by the caller. + +template +const unsigned char* +Sized_relobj_file::do_decompressed_section_contents( + unsigned int shndx, + section_size_type* plen, + bool* is_new) +{ + section_size_type buffer_size; + const unsigned char* buffer = this->do_section_contents(shndx, &buffer_size, + false); + + if (this->compressed_sections_ == NULL) + { + *plen = buffer_size; + *is_new = false; + return buffer; + } + + Compressed_section_map::const_iterator p = + this->compressed_sections_->find(shndx); + if (p == this->compressed_sections_->end()) + { + *plen = buffer_size; + *is_new = false; + return buffer; + } + + section_size_type uncompressed_size = p->second.size; + if (p->second.contents != NULL) + { + *plen = uncompressed_size; + *is_new = false; + return p->second.contents; + } + + unsigned char* uncompressed_data = new unsigned char[uncompressed_size]; + if (!decompress_input_section(buffer, + buffer_size, + uncompressed_data, + uncompressed_size)) + this->error(_("could not decompress section %s"), + this->do_section_name(shndx).c_str()); + + // We could cache the results in p->second.contents and store + // false in *IS_NEW, but build_compressed_section_map() would + // have done so if it had expected it to be profitable. If + // we reach this point, we expect to need the contents only + // once in this pass. + *plen = uncompressed_size; + *is_new = true; + return uncompressed_data; +} + +// Discard any buffers of uncompressed sections. This is done +// at the end of the Add_symbols task. + +template +void +Sized_relobj_file::do_discard_decompressed_sections() +{ + if (this->compressed_sections_ == NULL) + return; + + for (Compressed_section_map::iterator p = this->compressed_sections_->begin(); + p != this->compressed_sections_->end(); + ++p) + { + if (p->second.contents != NULL) + { + delete[] p->second.contents; + p->second.contents = NULL; + } + } +} + +// Input_objects methods. + +// Add a regular relocatable object to the list. Return false if this +// object should be ignored. + +bool +Input_objects::add_object(Object* obj) +{ + // Print the filename if the -t/--trace option is selected. + if (parameters->options().trace()) + gold_info("%s", obj->name().c_str()); + + if (!obj->is_dynamic()) + this->relobj_list_.push_back(static_cast(obj)); + else + { + // See if this is a duplicate SONAME. + Dynobj* dynobj = static_cast(obj); + const char* soname = dynobj->soname(); + + std::pair::iterator, bool> ins = + this->sonames_.insert(soname); + if (!ins.second) + { + // We have already seen a dynamic object with this soname. + return false; + } + + this->dynobj_list_.push_back(dynobj); + } + + // Add this object to the cross-referencer if requested. + if (parameters->options().user_set_print_symbol_counts() + || parameters->options().cref()) + { + if (this->cref_ == NULL) + this->cref_ = new Cref(); + this->cref_->add_object(obj); + } + + return true; +} + +// For each dynamic object, record whether we've seen all of its +// explicit dependencies. + +void +Input_objects::check_dynamic_dependencies() const +{ + bool issued_copy_dt_needed_error = false; + for (Dynobj_list::const_iterator p = this->dynobj_list_.begin(); + p != this->dynobj_list_.end(); + ++p) + { + const Dynobj::Needed& needed((*p)->needed()); + bool found_all = true; + Dynobj::Needed::const_iterator pneeded; + for (pneeded = needed.begin(); pneeded != needed.end(); ++pneeded) + { + if (this->sonames_.find(*pneeded) == this->sonames_.end()) + { + found_all = false; + break; + } + } + (*p)->set_has_unknown_needed_entries(!found_all); + + // --copy-dt-needed-entries aka --add-needed is a GNU ld option + // that gold does not support. However, they cause no trouble + // unless there is a DT_NEEDED entry that we don't know about; + // warn only in that case. + if (!found_all + && !issued_copy_dt_needed_error + && (parameters->options().copy_dt_needed_entries() + || parameters->options().add_needed())) + { + const char* optname; + if (parameters->options().copy_dt_needed_entries()) + optname = "--copy-dt-needed-entries"; + else + optname = "--add-needed"; + gold_error(_("%s is not supported but is required for %s in %s"), + optname, (*pneeded).c_str(), (*p)->name().c_str()); + issued_copy_dt_needed_error = true; + } + } +} + +// Start processing an archive. + +void +Input_objects::archive_start(Archive* archive) +{ + if (parameters->options().user_set_print_symbol_counts() + || parameters->options().cref()) + { + if (this->cref_ == NULL) + this->cref_ = new Cref(); + this->cref_->add_archive_start(archive); + } +} + +// Stop processing an archive. + +void +Input_objects::archive_stop(Archive* archive) +{ + if (parameters->options().user_set_print_symbol_counts() + || parameters->options().cref()) + this->cref_->add_archive_stop(archive); +} + +// Print symbol counts + +void +Input_objects::print_symbol_counts(const Symbol_table* symtab) const +{ + if (parameters->options().user_set_print_symbol_counts() + && this->cref_ != NULL) + this->cref_->print_symbol_counts(symtab); +} + +// Print a cross reference table. + +void +Input_objects::print_cref(const Symbol_table* symtab, FILE* f) const +{ + if (parameters->options().cref() && this->cref_ != NULL) + this->cref_->print_cref(symtab, f); +} + +// Relocate_info methods. + +// Return a string describing the location of a relocation when file +// and lineno information is not available. This is only used in +// error messages. + +template +std::string +Relocate_info::location(size_t, off_t offset) const +{ + Sized_dwarf_line_info line_info(this->object); + std::string ret = line_info.addr2line(this->data_shndx, offset, NULL); + if (!ret.empty()) + return ret; + + ret = this->object->name(); + + Symbol_location_info info; + if (this->object->get_symbol_location_info(this->data_shndx, offset, &info)) + { + if (!info.source_file.empty()) + { + ret += ":"; + ret += info.source_file; + } + ret += ":"; + if (info.enclosing_symbol_type == elfcpp::STT_FUNC) + ret += _("function "); + ret += info.enclosing_symbol_name; + return ret; + } + + ret += "("; + ret += this->object->section_name(this->data_shndx); + char buf[100]; + snprintf(buf, sizeof buf, "+0x%lx)", static_cast(offset)); + ret += buf; + return ret; +} + +} // End namespace gold. + +namespace +{ + +using namespace gold; + +// Read an ELF file with the header and return the appropriate +// instance of Object. + +template +Object* +make_elf_sized_object(const std::string& name, Input_file* input_file, + off_t offset, const elfcpp::Ehdr& ehdr, + bool* punconfigured) +{ + 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) + gold_fatal(_("%s: unsupported ELF machine number %d"), + name.c_str(), ehdr.get_e_machine()); + + if (!parameters->target_valid()) + set_parameters_target(target); + else if (target != ¶meters->target()) + { + if (punconfigured != NULL) + *punconfigured = true; + else + gold_error(_("%s: incompatible target"), name.c_str()); + return NULL; + } + + return target->make_elf_object(name, input_file, offset, + ehdr); +} + +} // End anonymous namespace. + +namespace gold +{ + +// Return whether INPUT_FILE is an ELF object. + +bool +is_elf_object(Input_file* input_file, off_t offset, + const unsigned char** start, int* read_size) +{ + off_t filesize = input_file->file().filesize(); + int want = elfcpp::Elf_recognizer::max_header_size; + if (filesize - offset < want) + want = filesize - offset; + + const unsigned char* p = input_file->file().get_view(offset, 0, want, + true, false); + *start = p; + *read_size = want; + + return elfcpp::Elf_recognizer::is_elf_file(p, want); +} + +// Read an ELF file and return the appropriate instance of Object. + +Object* +make_elf_object(const std::string& name, Input_file* input_file, off_t offset, + const unsigned char* p, section_offset_type bytes, + bool* punconfigured) +{ + if (punconfigured != NULL) + *punconfigured = false; + + std::string error; + bool big_endian = false; + int size = 0; + if (!elfcpp::Elf_recognizer::is_valid_header(p, bytes, &size, + &big_endian, &error)) + { + gold_error(_("%s: %s"), name.c_str(), error.c_str()); + return NULL; + } + + if (size == 32) + { + if (big_endian) + { +#ifdef HAVE_TARGET_32_BIG + elfcpp::Ehdr<32, true> ehdr(p); + return make_elf_sized_object<32, true>(name, input_file, + offset, ehdr, punconfigured); +#else + if (punconfigured != NULL) + *punconfigured = true; + else + gold_error(_("%s: not configured to support " + "32-bit big-endian object"), + name.c_str()); + return NULL; +#endif + } + else + { +#ifdef HAVE_TARGET_32_LITTLE + elfcpp::Ehdr<32, false> ehdr(p); + return make_elf_sized_object<32, false>(name, input_file, + offset, ehdr, punconfigured); +#else + if (punconfigured != NULL) + *punconfigured = true; + else + gold_error(_("%s: not configured to support " + "32-bit little-endian object"), + name.c_str()); + return NULL; +#endif + } + } + else if (size == 64) + { + if (big_endian) + { +#ifdef HAVE_TARGET_64_BIG + elfcpp::Ehdr<64, true> ehdr(p); + return make_elf_sized_object<64, true>(name, input_file, + offset, ehdr, punconfigured); +#else + if (punconfigured != NULL) + *punconfigured = true; + else + gold_error(_("%s: not configured to support " + "64-bit big-endian object"), + name.c_str()); + return NULL; +#endif + } + else + { +#ifdef HAVE_TARGET_64_LITTLE + elfcpp::Ehdr<64, false> ehdr(p); + return make_elf_sized_object<64, false>(name, input_file, + offset, ehdr, punconfigured); +#else + if (punconfigured != NULL) + *punconfigured = true; + else + gold_error(_("%s: not configured to support " + "64-bit little-endian object"), + name.c_str()); + return NULL; +#endif + } + } + else + gold_unreachable(); +} + +// Instantiate the templates we need. + +#ifdef HAVE_TARGET_32_LITTLE +template +void +Object::read_section_data<32, false>(elfcpp::Elf_file<32, false, Object>*, + Read_symbols_data*); +template +const unsigned char* +Object::find_shdr<32,false>(const unsigned char*, const char*, const char*, + section_size_type, const unsigned char*) const; +#endif + +#ifdef HAVE_TARGET_32_BIG +template +void +Object::read_section_data<32, true>(elfcpp::Elf_file<32, true, Object>*, + Read_symbols_data*); +template +const unsigned char* +Object::find_shdr<32,true>(const unsigned char*, const char*, const char*, + section_size_type, const unsigned char*) const; +#endif + +#ifdef HAVE_TARGET_64_LITTLE +template +void +Object::read_section_data<64, false>(elfcpp::Elf_file<64, false, Object>*, + Read_symbols_data*); +template +const unsigned char* +Object::find_shdr<64,false>(const unsigned char*, const char*, const char*, + section_size_type, const unsigned char*) const; +#endif + +#ifdef HAVE_TARGET_64_BIG +template +void +Object::read_section_data<64, true>(elfcpp::Elf_file<64, true, Object>*, + Read_symbols_data*); +template +const unsigned char* +Object::find_shdr<64,true>(const unsigned char*, const char*, const char*, + section_size_type, const unsigned char*) const; +#endif + +#ifdef HAVE_TARGET_32_LITTLE +template +class Sized_relobj<32, false>; + +template +class Sized_relobj_file<32, false>; +#endif + +#ifdef HAVE_TARGET_32_BIG +template +class Sized_relobj<32, true>; + +template +class Sized_relobj_file<32, true>; +#endif + +#ifdef HAVE_TARGET_64_LITTLE +template +class Sized_relobj<64, false>; + +template +class Sized_relobj_file<64, false>; +#endif + +#ifdef HAVE_TARGET_64_BIG +template +class Sized_relobj<64, true>; + +template +class Sized_relobj_file<64, true>; +#endif + +#ifdef HAVE_TARGET_32_LITTLE +template +struct Relocate_info<32, false>; +#endif + +#ifdef HAVE_TARGET_32_BIG +template +struct Relocate_info<32, true>; +#endif + +#ifdef HAVE_TARGET_64_LITTLE +template +struct Relocate_info<64, false>; +#endif + +#ifdef HAVE_TARGET_64_BIG +template +struct Relocate_info<64, true>; +#endif + +#ifdef HAVE_TARGET_32_LITTLE +template +void +Xindex::initialize_symtab_xindex<32, false>(Object*, unsigned int); + +template +void +Xindex::read_symtab_xindex<32, false>(Object*, unsigned int, + const unsigned char*); +#endif + +#ifdef HAVE_TARGET_32_BIG +template +void +Xindex::initialize_symtab_xindex<32, true>(Object*, unsigned int); + +template +void +Xindex::read_symtab_xindex<32, true>(Object*, unsigned int, + const unsigned char*); +#endif + +#ifdef HAVE_TARGET_64_LITTLE +template +void +Xindex::initialize_symtab_xindex<64, false>(Object*, unsigned int); + +template +void +Xindex::read_symtab_xindex<64, false>(Object*, unsigned int, + const unsigned char*); +#endif + +#ifdef HAVE_TARGET_64_BIG +template +void +Xindex::initialize_symtab_xindex<64, true>(Object*, unsigned int); + +template +void +Xindex::read_symtab_xindex<64, true>(Object*, unsigned int, + const unsigned char*); +#endif + +} // End namespace gold. diff --git a/binutils-2.25/gold/object.h b/binutils-2.25/gold/object.h new file mode 100644 index 00000000..88263b4b --- /dev/null +++ b/binutils-2.25/gold/object.h @@ -0,0 +1,2918 @@ +// object.h -- support for an object file for linking in gold -*- C++ -*- + +// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2012, 2013 +// Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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. + +#ifndef GOLD_OBJECT_H +#define GOLD_OBJECT_H + +#include +#include + +#include "elfcpp.h" +#include "elfcpp_file.h" +#include "fileread.h" +#include "target.h" +#include "archive.h" + +namespace gold +{ + +class General_options; +class Task; +class Cref; +class Layout; +class Output_data; +class Output_section; +class Output_file; +class Output_symtab_xindex; +class Pluginobj; +class Dynobj; +class Object_merge_map; +class Relocatable_relocs; +struct Symbols_data; + +template +class Stringpool_template; + +// Data to pass from read_symbols() to add_symbols(). + +struct Read_symbols_data +{ + Read_symbols_data() + : section_headers(NULL), section_names(NULL), symbols(NULL), + symbol_names(NULL), versym(NULL), verdef(NULL), verneed(NULL) + { } + + ~Read_symbols_data(); + + // Section headers. + File_view* section_headers; + // Section names. + File_view* section_names; + // Size of section name data in bytes. + section_size_type section_names_size; + // Symbol data. + File_view* symbols; + // Size of symbol data in bytes. + section_size_type symbols_size; + // Offset of external symbols within symbol data. This structure + // sometimes contains only external symbols, in which case this will + // be zero. Sometimes it contains all symbols. + section_offset_type external_symbols_offset; + // Symbol names. + File_view* symbol_names; + // Size of symbol name data in bytes. + section_size_type symbol_names_size; + + // Version information. This is only used on dynamic objects. + // Version symbol data (from SHT_GNU_versym section). + File_view* versym; + section_size_type versym_size; + // Version definition data (from SHT_GNU_verdef section). + File_view* verdef; + section_size_type verdef_size; + unsigned int verdef_info; + // Needed version data (from SHT_GNU_verneed section). + File_view* verneed; + section_size_type verneed_size; + unsigned int verneed_info; +}; + +// Information used to print error messages. + +struct Symbol_location_info +{ + std::string source_file; + std::string enclosing_symbol_name; + elfcpp::STT enclosing_symbol_type; +}; + +// Data about a single relocation section. This is read in +// read_relocs and processed in scan_relocs. + +struct Section_relocs +{ + Section_relocs() + : contents(NULL) + { } + + ~Section_relocs() + { delete this->contents; } + + // Index of reloc section. + unsigned int reloc_shndx; + // Index of section that relocs apply to. + unsigned int data_shndx; + // Contents of reloc section. + File_view* contents; + // Reloc section type. + unsigned int sh_type; + // Number of reloc entries. + size_t reloc_count; + // Output section. + Output_section* output_section; + // Whether this section has special handling for offsets. + bool needs_special_offset_handling; + // Whether the data section is allocated (has the SHF_ALLOC flag set). + bool is_data_section_allocated; +}; + +// Relocations in an object file. This is read in read_relocs and +// processed in scan_relocs. + +struct Read_relocs_data +{ + Read_relocs_data() + : local_symbols(NULL) + { } + + ~Read_relocs_data() + { delete this->local_symbols; } + + typedef std::vector Relocs_list; + // The relocations. + Relocs_list relocs; + // The local symbols. + File_view* local_symbols; +}; + +// The Xindex class manages section indexes for objects with more than +// 0xff00 sections. + +class Xindex +{ + public: + Xindex(int large_shndx_offset) + : large_shndx_offset_(large_shndx_offset), symtab_xindex_() + { } + + // Initialize the symtab_xindex_ array, given the object and the + // section index of the symbol table to use. + template + void + initialize_symtab_xindex(Object*, unsigned int symtab_shndx); + + // Read in the symtab_xindex_ array, given its section index. + // PSHDRS may optionally point to the section headers. + template + void + read_symtab_xindex(Object*, unsigned int xindex_shndx, + const unsigned char* pshdrs); + + // Symbol SYMNDX in OBJECT has a section of SHN_XINDEX; return the + // real section index. + unsigned int + sym_xindex_to_shndx(Object* object, unsigned int symndx); + + private: + // The type of the array giving the real section index for symbols + // whose st_shndx field holds SHN_XINDEX. + typedef std::vector Symtab_xindex; + + // Adjust a section index if necessary. This should only be called + // for ordinary section indexes. + unsigned int + adjust_shndx(unsigned int shndx) + { + if (shndx >= elfcpp::SHN_LORESERVE) + shndx += this->large_shndx_offset_; + return shndx; + } + + // Adjust to apply to large section indexes. + int large_shndx_offset_; + // The data from the SHT_SYMTAB_SHNDX section. + Symtab_xindex symtab_xindex_; +}; + +// A GOT offset list. A symbol may have more than one GOT offset +// (e.g., when mixing modules compiled with two different TLS models), +// but will usually have at most one. GOT_TYPE identifies the type of +// GOT entry; its values are specific to each target. + +class Got_offset_list +{ + public: + Got_offset_list() + : got_type_(-1U), got_offset_(0), got_next_(NULL) + { } + + Got_offset_list(unsigned int got_type, unsigned int got_offset) + : got_type_(got_type), got_offset_(got_offset), got_next_(NULL) + { } + + ~Got_offset_list() + { + if (this->got_next_ != NULL) + { + delete this->got_next_; + this->got_next_ = NULL; + } + } + + // Initialize the fields to their default values. + void + init() + { + this->got_type_ = -1U; + this->got_offset_ = 0; + this->got_next_ = NULL; + } + + // Set the offset for the GOT entry of type GOT_TYPE. + void + set_offset(unsigned int got_type, unsigned int got_offset) + { + if (this->got_type_ == -1U) + { + this->got_type_ = got_type; + this->got_offset_ = got_offset; + } + else + { + for (Got_offset_list* g = this; g != NULL; g = g->got_next_) + { + if (g->got_type_ == got_type) + { + g->got_offset_ = got_offset; + return; + } + } + Got_offset_list* g = new Got_offset_list(got_type, got_offset); + g->got_next_ = this->got_next_; + this->got_next_ = g; + } + } + + // Return the offset for a GOT entry of type GOT_TYPE. + unsigned int + get_offset(unsigned int got_type) const + { + for (const Got_offset_list* g = this; g != NULL; g = g->got_next_) + { + if (g->got_type_ == got_type) + return g->got_offset_; + } + return -1U; + } + + // Return a pointer to the list, or NULL if the list is empty. + const Got_offset_list* + get_list() const + { + if (this->got_type_ == -1U) + return NULL; + return this; + } + + // Abstract visitor class for iterating over GOT offsets. + class Visitor + { + public: + Visitor() + { } + + virtual + ~Visitor() + { } + + virtual void + visit(unsigned int, unsigned int) = 0; + }; + + // Loop over all GOT offset entries, calling a visitor class V for each. + void + for_all_got_offsets(Visitor* v) const + { + if (this->got_type_ == -1U) + return; + for (const Got_offset_list* g = this; g != NULL; g = g->got_next_) + v->visit(g->got_type_, g->got_offset_); + } + + private: + unsigned int got_type_; + unsigned int got_offset_; + Got_offset_list* got_next_; +}; + +// Object is an abstract base class which represents either a 32-bit +// or a 64-bit input object. This can be a regular object file +// (ET_REL) or a shared object (ET_DYN). + +class Object +{ + public: + typedef std::vector Symbols; + + // NAME is the name of the object as we would report it to the user + // (e.g., libfoo.a(bar.o) if this is in an archive. INPUT_FILE is + // used to read the file. OFFSET is the offset within the input + // file--0 for a .o or .so file, something else for a .a file. + Object(const std::string& name, Input_file* input_file, bool is_dynamic, + off_t offset = 0) + : name_(name), input_file_(input_file), offset_(offset), shnum_(-1U), + is_dynamic_(is_dynamic), is_needed_(false), uses_split_stack_(false), + has_no_split_stack_(false), no_export_(false), + is_in_system_directory_(false), as_needed_(false), xindex_(NULL) + { + if (input_file != NULL) + { + input_file->file().add_object(); + this->is_in_system_directory_ = input_file->is_in_system_directory(); + this->as_needed_ = input_file->options().as_needed(); + } + } + + virtual ~Object() + { + if (this->input_file_ != NULL) + this->input_file_->file().remove_object(); + } + + // Return the name of the object as we would report it to the user. + const std::string& + name() const + { return this->name_; } + + // Get the offset into the file. + off_t + offset() const + { return this->offset_; } + + // Return whether this is a dynamic object. + bool + is_dynamic() const + { return this->is_dynamic_; } + + // Return whether this object is needed--true if it is a dynamic + // object which defines some symbol referenced by a regular object. + // We keep the flag here rather than in Dynobj for convenience when + // setting it. + bool + is_needed() const + { return this->is_needed_; } + + // Record that this object is needed. + void + set_is_needed() + { this->is_needed_ = true; } + + // Return whether this object was compiled with -fsplit-stack. + bool + uses_split_stack() const + { return this->uses_split_stack_; } + + // Return whether this object contains any functions compiled with + // the no_split_stack attribute. + bool + has_no_split_stack() const + { return this->has_no_split_stack_; } + + // Returns NULL for Objects that are not dynamic objects. This method + // is overridden in the Dynobj class. + Dynobj* + dynobj() + { return this->do_dynobj(); } + + // Returns NULL for Objects that are not plugin objects. This method + // is overridden in the Pluginobj class. + Pluginobj* + pluginobj() + { return this->do_pluginobj(); } + + // Get the file. We pass on const-ness. + Input_file* + input_file() + { + gold_assert(this->input_file_ != NULL); + return this->input_file_; + } + + const Input_file* + input_file() const + { + gold_assert(this->input_file_ != NULL); + return this->input_file_; + } + + // Lock the underlying file. + void + lock(const Task* t) + { + if (this->input_file_ != NULL) + this->input_file_->file().lock(t); + } + + // Unlock the underlying file. + void + unlock(const Task* t) + { + if (this->input_file_ != NULL) + this->input_file()->file().unlock(t); + } + + // Return whether the underlying file is locked. + bool + is_locked() const + { return this->input_file_ != NULL && this->input_file_->file().is_locked(); } + + // Return the token, so that the task can be queued. + Task_token* + token() + { + if (this->input_file_ == NULL) + return NULL; + return this->input_file()->file().token(); + } + + // Release the underlying file. + void + release() + { + if (this->input_file_ != NULL) + this->input_file()->file().release(); + } + + // Return whether we should just read symbols from this file. + bool + just_symbols() const + { return this->input_file()->just_symbols(); } + + // Return whether this is an incremental object. + bool + is_incremental() const + { return this->do_is_incremental(); } + + // Return the last modified time of the file. + Timespec + get_mtime() + { return this->do_get_mtime(); } + + // Get the number of sections. + unsigned int + shnum() const + { return this->shnum_; } + + // Return a view of the contents of a section. Set *PLEN to the + // size. CACHE is a hint as in File_read::get_view. + const unsigned char* + section_contents(unsigned int shndx, section_size_type* plen, bool cache); + + // Adjust a symbol's section index as needed. SYMNDX is the index + // of the symbol and SHNDX is the symbol's section from + // get_st_shndx. This returns the section index. It sets + // *IS_ORDINARY to indicate whether this is a normal section index, + // rather than a special code between SHN_LORESERVE and + // SHN_HIRESERVE. + unsigned int + adjust_sym_shndx(unsigned int symndx, unsigned int shndx, bool* is_ordinary) + { + if (shndx < elfcpp::SHN_LORESERVE) + *is_ordinary = true; + else if (shndx == elfcpp::SHN_XINDEX) + { + if (this->xindex_ == NULL) + this->xindex_ = this->do_initialize_xindex(); + shndx = this->xindex_->sym_xindex_to_shndx(this, symndx); + *is_ordinary = true; + } + else + *is_ordinary = false; + return shndx; + } + + // Return the size of a section given a section index. + uint64_t + section_size(unsigned int shndx) + { return this->do_section_size(shndx); } + + // Return the name of a section given a section index. + std::string + section_name(unsigned int shndx) + { return this->do_section_name(shndx); } + + // Return the section flags given a section index. + uint64_t + section_flags(unsigned int shndx) + { return this->do_section_flags(shndx); } + + // Return the section entsize given a section index. + uint64_t + section_entsize(unsigned int shndx) + { return this->do_section_entsize(shndx); } + + // Return the section address given a section index. + uint64_t + section_address(unsigned int shndx) + { return this->do_section_address(shndx); } + + // Return the section type given a section index. + unsigned int + section_type(unsigned int shndx) + { return this->do_section_type(shndx); } + + // Return the section link field given a section index. + unsigned int + section_link(unsigned int shndx) + { return this->do_section_link(shndx); } + + // Return the section info field given a section index. + unsigned int + section_info(unsigned int shndx) + { return this->do_section_info(shndx); } + + // Return the required section alignment given a section index. + uint64_t + section_addralign(unsigned int shndx) + { return this->do_section_addralign(shndx); } + + // Return the output section given a section index. + Output_section* + output_section(unsigned int shndx) const + { return this->do_output_section(shndx); } + + // Given a section index, return its address. + // The return value will be -1U if the section is specially mapped, + // such as a merge section. + uint64_t + output_section_address(unsigned int shndx) + { return this->do_output_section_address(shndx); } + + // Given a section index, return the offset in the Output_section. + // The return value will be -1U if the section is specially mapped, + // such as a merge section. + uint64_t + output_section_offset(unsigned int shndx) const + { return this->do_output_section_offset(shndx); } + + // Read the symbol information. + void + read_symbols(Read_symbols_data* sd) + { return this->do_read_symbols(sd); } + + // Pass sections which should be included in the link to the Layout + // object, and record where the sections go in the output file. + void + layout(Symbol_table* symtab, Layout* layout, Read_symbols_data* sd) + { this->do_layout(symtab, layout, sd); } + + // Add symbol information to the global symbol table. + void + add_symbols(Symbol_table* symtab, Read_symbols_data* sd, Layout *layout) + { this->do_add_symbols(symtab, sd, layout); } + + // Add symbol information to the global symbol table. + Archive::Should_include + should_include_member(Symbol_table* symtab, Layout* layout, + Read_symbols_data* sd, std::string* why) + { return this->do_should_include_member(symtab, layout, sd, why); } + + // Iterate over global symbols, calling a visitor class V for each. + void + for_all_global_symbols(Read_symbols_data* sd, + Library_base::Symbol_visitor_base* v) + { return this->do_for_all_global_symbols(sd, v); } + + // Iterate over local symbols, calling a visitor class V for each GOT offset + // associated with a local symbol. + void + for_all_local_got_entries(Got_offset_list::Visitor* v) const + { this->do_for_all_local_got_entries(v); } + + // Functions and types for the elfcpp::Elf_file interface. This + // permit us to use Object as the File template parameter for + // elfcpp::Elf_file. + + // The View class is returned by view. It must support a single + // method, data(). This is trivial, because get_view does what we + // need. + class View + { + public: + View(const unsigned char* p) + : p_(p) + { } + + const unsigned char* + data() const + { return this->p_; } + + private: + const unsigned char* p_; + }; + + // Return a View. + View + view(off_t file_offset, section_size_type data_size) + { return View(this->get_view(file_offset, data_size, true, true)); } + + // Report an error. + void + error(const char* format, ...) const ATTRIBUTE_PRINTF_2; + + // A location in the file. + struct Location + { + off_t file_offset; + off_t data_size; + + Location(off_t fo, section_size_type ds) + : file_offset(fo), data_size(ds) + { } + }; + + // Get a View given a Location. + View view(Location loc) + { return View(this->get_view(loc.file_offset, loc.data_size, true, true)); } + + // Get a view into the underlying file. + const unsigned char* + get_view(off_t start, section_size_type size, bool aligned, bool cache) + { + return this->input_file()->file().get_view(this->offset_, start, size, + aligned, cache); + } + + // Get a lasting view into the underlying file. + File_view* + get_lasting_view(off_t start, section_size_type size, bool aligned, + bool cache) + { + return this->input_file()->file().get_lasting_view(this->offset_, start, + size, aligned, cache); + } + + // Read data from the underlying file. + void + read(off_t start, section_size_type size, void* p) + { this->input_file()->file().read(start + this->offset_, size, p); } + + // Read multiple data from the underlying file. + void + read_multiple(const File_read::Read_multiple& rm) + { this->input_file()->file().read_multiple(this->offset_, rm); } + + // Stop caching views in the underlying file. + void + clear_view_cache_marks() + { + if (this->input_file_ != NULL) + this->input_file_->file().clear_view_cache_marks(); + } + + // Get the number of global symbols defined by this object, and the + // number of the symbols whose final definition came from this + // object. + void + get_global_symbol_counts(const Symbol_table* symtab, size_t* defined, + size_t* used) const + { this->do_get_global_symbol_counts(symtab, defined, used); } + + // Get the symbols defined in this object. + const Symbols* + get_global_symbols() const + { return this->do_get_global_symbols(); } + + // Set flag that this object was found in a system directory. + void + set_is_in_system_directory() + { this->is_in_system_directory_ = true; } + + // Return whether this object was found in a system directory. + bool + is_in_system_directory() const + { return this->is_in_system_directory_; } + + // Set flag that this object was linked with --as-needed. + void + set_as_needed() + { this->as_needed_ = true; } + + // Return whether this object was linked with --as-needed. + bool + as_needed() const + { return this->as_needed_; } + + // Return whether we found this object by searching a directory. + bool + searched_for() const + { return this->input_file()->will_search_for(); } + + bool + no_export() const + { return this->no_export_; } + + void + set_no_export(bool value) + { this->no_export_ = value; } + + // Return TRUE if the section is a compressed debug section, and set + // *UNCOMPRESSED_SIZE to the size of the uncompressed data. + bool + section_is_compressed(unsigned int shndx, + section_size_type* uncompressed_size) const + { return this->do_section_is_compressed(shndx, uncompressed_size); } + + // Return a view of the decompressed contents of a section. Set *PLEN + // to the size. Set *IS_NEW to true if the contents need to be freed + // by the caller. + const unsigned char* + decompressed_section_contents(unsigned int shndx, section_size_type* plen, + bool* is_cached) + { return this->do_decompressed_section_contents(shndx, plen, is_cached); } + + // Discard any buffers of decompressed sections. This is done + // at the end of the Add_symbols task. + void + discard_decompressed_sections() + { this->do_discard_decompressed_sections(); } + + // Return the index of the first incremental relocation for symbol SYMNDX. + unsigned int + get_incremental_reloc_base(unsigned int symndx) const + { return this->do_get_incremental_reloc_base(symndx); } + + // Return the number of incremental relocations for symbol SYMNDX. + unsigned int + get_incremental_reloc_count(unsigned int symndx) const + { return this->do_get_incremental_reloc_count(symndx); } + + protected: + // Returns NULL for Objects that are not dynamic objects. This method + // is overridden in the Dynobj class. + virtual Dynobj* + do_dynobj() + { return NULL; } + + // Returns NULL for Objects that are not plugin objects. This method + // is overridden in the Pluginobj class. + virtual Pluginobj* + do_pluginobj() + { return NULL; } + + // Return TRUE if this is an incremental (unchanged) input file. + // We return FALSE by default; the incremental object classes + // override this method. + virtual bool + do_is_incremental() const + { return false; } + + // Return the last modified time of the file. This method may be + // overridden for subclasses that don't use an actual file (e.g., + // Incremental objects). + virtual Timespec + do_get_mtime() + { return this->input_file()->file().get_mtime(); } + + // Read the symbols--implemented by child class. + virtual void + do_read_symbols(Read_symbols_data*) = 0; + + // Lay out sections--implemented by child class. + virtual void + do_layout(Symbol_table*, Layout*, Read_symbols_data*) = 0; + + // Add symbol information to the global symbol table--implemented by + // child class. + virtual void + do_add_symbols(Symbol_table*, Read_symbols_data*, Layout*) = 0; + + virtual Archive::Should_include + do_should_include_member(Symbol_table* symtab, Layout*, Read_symbols_data*, + std::string* why) = 0; + + // Iterate over global symbols, calling a visitor class V for each. + virtual void + do_for_all_global_symbols(Read_symbols_data* sd, + Library_base::Symbol_visitor_base* v) = 0; + + // Iterate over local symbols, calling a visitor class V for each GOT offset + // associated with a local symbol. + virtual void + do_for_all_local_got_entries(Got_offset_list::Visitor* v) const = 0; + + // Return the location of the contents of a section. Implemented by + // child class. + virtual const unsigned char* + do_section_contents(unsigned int shndx, section_size_type* plen, + bool cache) = 0; + + // Get the size of a section--implemented by child class. + virtual uint64_t + do_section_size(unsigned int shndx) = 0; + + // Get the name of a section--implemented by child class. + virtual std::string + do_section_name(unsigned int shndx) = 0; + + // Get section flags--implemented by child class. + virtual uint64_t + do_section_flags(unsigned int shndx) = 0; + + // Get section entsize--implemented by child class. + virtual uint64_t + do_section_entsize(unsigned int shndx) = 0; + + // Get section address--implemented by child class. + virtual uint64_t + do_section_address(unsigned int shndx) = 0; + + // Get section type--implemented by child class. + virtual unsigned int + do_section_type(unsigned int shndx) = 0; + + // Get section link field--implemented by child class. + virtual unsigned int + do_section_link(unsigned int shndx) = 0; + + // Get section info field--implemented by child class. + virtual unsigned int + do_section_info(unsigned int shndx) = 0; + + // Get section alignment--implemented by child class. + virtual uint64_t + do_section_addralign(unsigned int shndx) = 0; + + // Return the output section given a section index--implemented + // by child class. + virtual Output_section* + do_output_section(unsigned int) const + { gold_unreachable(); } + + // Get the address of a section--implemented by child class. + virtual uint64_t + do_output_section_address(unsigned int) + { gold_unreachable(); } + + // Get the offset of a section--implemented by child class. + virtual uint64_t + do_output_section_offset(unsigned int) const + { gold_unreachable(); } + + // Return the Xindex structure to use. + virtual Xindex* + do_initialize_xindex() = 0; + + // Implement get_global_symbol_counts--implemented by child class. + virtual void + do_get_global_symbol_counts(const Symbol_table*, size_t*, size_t*) const = 0; + + virtual const Symbols* + do_get_global_symbols() const = 0; + + // Set the number of sections. + void + set_shnum(int shnum) + { this->shnum_ = shnum; } + + // Functions used by both Sized_relobj_file and Sized_dynobj. + + // Read the section data into a Read_symbols_data object. + template + void + read_section_data(elfcpp::Elf_file*, + Read_symbols_data*); + + // Find the section header with the given NAME. If HDR is non-NULL + // then it is a section header returned from a previous call to this + // function and the next section header with the same name will be + // returned. + template + const unsigned char* + find_shdr(const unsigned char* pshdrs, const char* name, + const char* names, section_size_type names_size, + const unsigned char* hdr) const; + + // Let the child class initialize the xindex object directly. + void + set_xindex(Xindex* xindex) + { + gold_assert(this->xindex_ == NULL); + this->xindex_ = xindex; + } + + // If NAME is the name of a special .gnu.warning section, arrange + // for the warning to be issued. SHNDX is the section index. + // Return whether it is a warning section. + bool + handle_gnu_warning_section(const char* name, unsigned int shndx, + Symbol_table*); + + // If NAME is the name of the special section which indicates that + // this object was compiled with -fsplit-stack, mark it accordingly, + // and return true. Otherwise return false. + bool + handle_split_stack_section(const char* name); + + // Return TRUE if the section is a compressed debug section, and set + // *UNCOMPRESSED_SIZE to the size of the uncompressed data. + virtual bool + do_section_is_compressed(unsigned int, section_size_type*) const + { return false; } + + // Return a view of the decompressed contents of a section. Set *PLEN + // to the size. This default implementation simply returns the + // raw section contents and sets *IS_NEW to false to indicate + // that the contents do not need to be freed by the caller. + // This function must be overridden for any types of object files + // that might contain compressed sections. + virtual const unsigned char* + do_decompressed_section_contents(unsigned int shndx, + section_size_type* plen, + bool* is_new) + { + *is_new = false; + return this->do_section_contents(shndx, plen, false); + } + + // Discard any buffers of decompressed sections. This is done + // at the end of the Add_symbols task. + virtual void + do_discard_decompressed_sections() + { } + + // Return the index of the first incremental relocation for symbol SYMNDX-- + // implemented by child class. + virtual unsigned int + do_get_incremental_reloc_base(unsigned int) const + { gold_unreachable(); } + + // Return the number of incremental relocations for symbol SYMNDX-- + // implemented by child class. + virtual unsigned int + do_get_incremental_reloc_count(unsigned int) const + { gold_unreachable(); } + + private: + // This class may not be copied. + Object(const Object&); + Object& operator=(const Object&); + + // Name of object as printed to user. + std::string name_; + // For reading the file. + Input_file* input_file_; + // Offset within the file--0 for an object file, non-0 for an + // archive. + off_t offset_; + // Number of input sections. + unsigned int shnum_; + // Whether this is a dynamic object. + bool is_dynamic_ : 1; + // Whether this object is needed. This is only set for dynamic + // objects, and means that the object defined a symbol which was + // used by a reference from a regular object. + bool is_needed_ : 1; + // Whether this object was compiled with -fsplit-stack. + bool uses_split_stack_ : 1; + // Whether this object contains any functions compiled with the + // no_split_stack attribute. + bool has_no_split_stack_ : 1; + // True if exclude this object from automatic symbol export. + // This is used only for archive objects. + bool no_export_ : 1; + // True if the object was found in a system directory. + bool is_in_system_directory_ : 1; + // True if the object was linked with --as-needed. + bool as_needed_ : 1; + // Many sections for objects with more than SHN_LORESERVE sections. + Xindex* xindex_; +}; + +// A regular object (ET_REL). This is an abstract base class itself. +// The implementation is the template class Sized_relobj_file. + +class Relobj : public Object +{ + public: + Relobj(const std::string& name, Input_file* input_file, off_t offset = 0) + : Object(name, input_file, false, offset), + output_sections_(), + map_to_relocatable_relocs_(NULL), + object_merge_map_(NULL), + relocs_must_follow_section_writes_(false), + sd_(NULL), + reloc_counts_(NULL), + reloc_bases_(NULL), + first_dyn_reloc_(0), + dyn_reloc_count_(0) + { } + + // During garbage collection, the Read_symbols_data pass for + // each object is stored as layout needs to be done after + // reloc processing. + Symbols_data* + get_symbols_data() + { return this->sd_; } + + // Decides which section names have to be included in the worklist + // as roots. + bool + is_section_name_included(const char* name); + + void + copy_symbols_data(Symbols_data* gc_sd, Read_symbols_data* sd, + unsigned int section_header_size); + + void + set_symbols_data(Symbols_data* sd) + { this->sd_ = sd; } + + // During garbage collection, the Read_relocs pass for all objects + // is done before scanning the relocs. In that case, this->rd_ is + // used to store the information from Read_relocs for each object. + // This data is also used to compute the list of relevant sections. + Read_relocs_data* + get_relocs_data() + { return this->rd_; } + + void + set_relocs_data(Read_relocs_data* rd) + { this->rd_ = rd; } + + virtual bool + is_output_section_offset_invalid(unsigned int shndx) const = 0; + + // Read the relocs. + void + read_relocs(Read_relocs_data* rd) + { return this->do_read_relocs(rd); } + + // Process the relocs, during garbage collection only. + void + gc_process_relocs(Symbol_table* symtab, Layout* layout, Read_relocs_data* rd) + { return this->do_gc_process_relocs(symtab, layout, rd); } + + // Scan the relocs and adjust the symbol table. + void + scan_relocs(Symbol_table* symtab, Layout* layout, Read_relocs_data* rd) + { return this->do_scan_relocs(symtab, layout, rd); } + + // Return the value of the local symbol whose index is SYMNDX, plus + // ADDEND. ADDEND is passed in so that we can correctly handle the + // section symbol for a merge section. + uint64_t + local_symbol_value(unsigned int symndx, uint64_t addend) const + { return this->do_local_symbol_value(symndx, addend); } + + // Return the PLT offset for a local symbol. It is an error to call + // this if it doesn't have one. + unsigned int + local_plt_offset(unsigned int symndx) const + { return this->do_local_plt_offset(symndx); } + + // Return whether the local symbol SYMNDX has a GOT offset of type + // GOT_TYPE. + bool + local_has_got_offset(unsigned int symndx, unsigned int got_type) const + { return this->do_local_has_got_offset(symndx, got_type); } + + // Return the GOT offset of type GOT_TYPE of the local symbol + // SYMNDX. It is an error to call this if the symbol does not have + // a GOT offset of the specified type. + unsigned int + local_got_offset(unsigned int symndx, unsigned int got_type) const + { return this->do_local_got_offset(symndx, got_type); } + + // Set the GOT offset with type GOT_TYPE of the local symbol SYMNDX + // to GOT_OFFSET. + void + set_local_got_offset(unsigned int symndx, unsigned int got_type, + unsigned int got_offset) + { this->do_set_local_got_offset(symndx, got_type, got_offset); } + + // Return whether the local symbol SYMNDX is a TLS symbol. + bool + local_is_tls(unsigned int symndx) const + { return this->do_local_is_tls(symndx); } + + // The number of local symbols in the input symbol table. + virtual unsigned int + local_symbol_count() const + { return this->do_local_symbol_count(); } + + // The number of local symbols in the output symbol table. + virtual unsigned int + output_local_symbol_count() const + { return this->do_output_local_symbol_count(); } + + // The file offset for local symbols in the output symbol table. + virtual off_t + local_symbol_offset() const + { return this->do_local_symbol_offset(); } + + // Initial local symbol processing: count the number of local symbols + // in the output symbol table and dynamic symbol table; add local symbol + // names to *POOL and *DYNPOOL. + void + count_local_symbols(Stringpool_template* pool, + Stringpool_template* dynpool) + { return this->do_count_local_symbols(pool, dynpool); } + + // Set the values of the local symbols, set the output symbol table + // indexes for the local variables, and set the offset where local + // symbol information will be stored. Returns the new local symbol index. + unsigned int + finalize_local_symbols(unsigned int index, off_t off, Symbol_table* symtab) + { return this->do_finalize_local_symbols(index, off, symtab); } + + // Set the output dynamic symbol table indexes for the local variables. + unsigned int + set_local_dynsym_indexes(unsigned int index) + { return this->do_set_local_dynsym_indexes(index); } + + // Set the offset where local dynamic symbol information will be stored. + unsigned int + set_local_dynsym_offset(off_t off) + { return this->do_set_local_dynsym_offset(off); } + + // Record a dynamic relocation against an input section from this object. + void + add_dyn_reloc(unsigned int index) + { + if (this->dyn_reloc_count_ == 0) + this->first_dyn_reloc_ = index; + ++this->dyn_reloc_count_; + } + + // Return the index of the first dynamic relocation. + unsigned int + first_dyn_reloc() const + { return this->first_dyn_reloc_; } + + // Return the count of dynamic relocations. + unsigned int + dyn_reloc_count() const + { return this->dyn_reloc_count_; } + + // Relocate the input sections and write out the local symbols. + void + relocate(const Symbol_table* symtab, const Layout* layout, Output_file* of) + { return this->do_relocate(symtab, layout, of); } + + // Return whether an input section is being included in the link. + bool + is_section_included(unsigned int shndx) const + { + gold_assert(shndx < this->output_sections_.size()); + return this->output_sections_[shndx] != NULL; + } + + // The output section of the input section with index SHNDX. + // This is only used currently to remove a section from the link in + // relaxation. + void + set_output_section(unsigned int shndx, Output_section* os) + { + gold_assert(shndx < this->output_sections_.size()); + this->output_sections_[shndx] = os; + } + + // Set the offset of an input section within its output section. + void + set_section_offset(unsigned int shndx, uint64_t off) + { this->do_set_section_offset(shndx, off); } + + // Return true if we need to wait for output sections to be written + // before we can apply relocations. This is true if the object has + // any relocations for sections which require special handling, such + // as the exception frame section. + bool + relocs_must_follow_section_writes() const + { return this->relocs_must_follow_section_writes_; } + + // Return the object merge map. + Object_merge_map* + merge_map() const + { return this->object_merge_map_; } + + // Set the object merge map. + void + set_merge_map(Object_merge_map* object_merge_map) + { + gold_assert(this->object_merge_map_ == NULL); + this->object_merge_map_ = object_merge_map; + } + + // Record the relocatable reloc info for an input reloc section. + void + set_relocatable_relocs(unsigned int reloc_shndx, Relocatable_relocs* rr) + { + gold_assert(reloc_shndx < this->shnum()); + (*this->map_to_relocatable_relocs_)[reloc_shndx] = rr; + } + + // Get the relocatable reloc info for an input reloc section. + Relocatable_relocs* + relocatable_relocs(unsigned int reloc_shndx) + { + gold_assert(reloc_shndx < this->shnum()); + return (*this->map_to_relocatable_relocs_)[reloc_shndx]; + } + + // Layout sections whose layout was deferred while waiting for + // input files from a plugin. + void + layout_deferred_sections(Layout* layout) + { this->do_layout_deferred_sections(layout); } + + // Return the index of the first incremental relocation for symbol SYMNDX. + virtual unsigned int + do_get_incremental_reloc_base(unsigned int symndx) const + { return this->reloc_bases_[symndx]; } + + // Return the number of incremental relocations for symbol SYMNDX. + virtual unsigned int + do_get_incremental_reloc_count(unsigned int symndx) const + { return this->reloc_counts_[symndx]; } + + // Return the word size of the object file. + int + elfsize() const + { return this->do_elfsize(); } + + // Return TRUE if this is a big-endian object file. + bool + is_big_endian() const + { return this->do_is_big_endian(); } + + protected: + // The output section to be used for each input section, indexed by + // the input section number. The output section is NULL if the + // input section is to be discarded. + typedef std::vector Output_sections; + + // Read the relocs--implemented by child class. + virtual void + do_read_relocs(Read_relocs_data*) = 0; + + // Process the relocs--implemented by child class. + virtual void + do_gc_process_relocs(Symbol_table*, Layout*, Read_relocs_data*) = 0; + + // Scan the relocs--implemented by child class. + virtual void + do_scan_relocs(Symbol_table*, Layout*, Read_relocs_data*) = 0; + + // Return the value of a local symbol. + virtual uint64_t + do_local_symbol_value(unsigned int symndx, uint64_t addend) const = 0; + + // Return the PLT offset of a local symbol. + virtual unsigned int + do_local_plt_offset(unsigned int symndx) const = 0; + + // Return whether a local symbol has a GOT offset of a given type. + virtual bool + do_local_has_got_offset(unsigned int symndx, + unsigned int got_type) const = 0; + + // Return the GOT offset of a given type of a local symbol. + virtual unsigned int + do_local_got_offset(unsigned int symndx, unsigned int got_type) const = 0; + + // Set the GOT offset with a given type for a local symbol. + virtual void + do_set_local_got_offset(unsigned int symndx, unsigned int got_type, + unsigned int got_offset) = 0; + + // Return whether local symbol SYMNDX is a TLS symbol. + virtual bool + do_local_is_tls(unsigned int symndx) const = 0; + + // Return the number of local symbols--implemented by child class. + virtual unsigned int + do_local_symbol_count() const = 0; + + // Return the number of output local symbols--implemented by child class. + virtual unsigned int + do_output_local_symbol_count() const = 0; + + // Return the file offset for local symbols--implemented by child class. + virtual off_t + do_local_symbol_offset() const = 0; + + // Count local symbols--implemented by child class. + virtual void + do_count_local_symbols(Stringpool_template*, + Stringpool_template*) = 0; + + // Finalize the local symbols. Set the output symbol table indexes + // for the local variables, and set the offset where local symbol + // information will be stored. + virtual unsigned int + do_finalize_local_symbols(unsigned int, off_t, Symbol_table*) = 0; + + // Set the output dynamic symbol table indexes for the local variables. + virtual unsigned int + do_set_local_dynsym_indexes(unsigned int) = 0; + + // Set the offset where local dynamic symbol information will be stored. + virtual unsigned int + do_set_local_dynsym_offset(off_t) = 0; + + // Relocate the input sections and write out the local + // symbols--implemented by child class. + virtual void + do_relocate(const Symbol_table* symtab, const Layout*, Output_file* of) = 0; + + // Set the offset of a section--implemented by child class. + virtual void + do_set_section_offset(unsigned int shndx, uint64_t off) = 0; + + // Layout sections whose layout was deferred while waiting for + // input files from a plugin--implemented by child class. + virtual void + do_layout_deferred_sections(Layout*) = 0; + + // Given a section index, return the corresponding Output_section. + // The return value will be NULL if the section is not included in + // the link. + Output_section* + do_output_section(unsigned int shndx) const + { + gold_assert(shndx < this->output_sections_.size()); + return this->output_sections_[shndx]; + } + + // Return the vector mapping input sections to output sections. + Output_sections& + output_sections() + { return this->output_sections_; } + + const Output_sections& + output_sections() const + { return this->output_sections_; } + + // Set the size of the relocatable relocs array. + void + size_relocatable_relocs() + { + this->map_to_relocatable_relocs_ = + new std::vector(this->shnum()); + } + + // Record that we must wait for the output sections to be written + // before applying relocations. + void + set_relocs_must_follow_section_writes() + { this->relocs_must_follow_section_writes_ = true; } + + // Allocate the array for counting incremental relocations. + void + allocate_incremental_reloc_counts() + { + unsigned int nsyms = this->do_get_global_symbols()->size(); + this->reloc_counts_ = new unsigned int[nsyms]; + gold_assert(this->reloc_counts_ != NULL); + memset(this->reloc_counts_, 0, nsyms * sizeof(unsigned int)); + } + + // Record a relocation in this object referencing global symbol SYMNDX. + // Used for tracking incremental link information. + void + count_incremental_reloc(unsigned int symndx) + { + unsigned int nsyms = this->do_get_global_symbols()->size(); + gold_assert(symndx < nsyms); + gold_assert(this->reloc_counts_ != NULL); + ++this->reloc_counts_[symndx]; + } + + // Finalize the incremental relocation information. + void + finalize_incremental_relocs(Layout* layout, bool clear_counts); + + // Return the index of the next relocation to be written for global symbol + // SYMNDX. Only valid after finalize_incremental_relocs() has been called. + unsigned int + next_incremental_reloc_index(unsigned int symndx) + { + unsigned int nsyms = this->do_get_global_symbols()->size(); + + gold_assert(this->reloc_counts_ != NULL); + gold_assert(this->reloc_bases_ != NULL); + gold_assert(symndx < nsyms); + + unsigned int counter = this->reloc_counts_[symndx]++; + return this->reloc_bases_[symndx] + counter; + } + + // Return the word size of the object file-- + // implemented by child class. + virtual int + do_elfsize() const = 0; + + // Return TRUE if this is a big-endian object file-- + // implemented by child class. + virtual bool + do_is_big_endian() const = 0; + + private: + // Mapping from input sections to output section. + Output_sections output_sections_; + // Mapping from input section index to the information recorded for + // the relocations. This is only used for a relocatable link. + std::vector* map_to_relocatable_relocs_; + // Mappings for merge sections. This is managed by the code in the + // Merge_map class. + Object_merge_map* object_merge_map_; + // Whether we need to wait for output sections to be written before + // we can apply relocations. + bool relocs_must_follow_section_writes_; + // Used to store the relocs data computed by the Read_relocs pass. + // Used during garbage collection of unused sections. + Read_relocs_data* rd_; + // Used to store the symbols data computed by the Read_symbols pass. + // Again used during garbage collection when laying out referenced + // sections. + gold::Symbols_data* sd_; + // Per-symbol counts of relocations, for incremental links. + unsigned int* reloc_counts_; + // Per-symbol base indexes of relocations, for incremental links. + unsigned int* reloc_bases_; + // Index of the first dynamic relocation for this object. + unsigned int first_dyn_reloc_; + // Count of dynamic relocations for this object. + unsigned int dyn_reloc_count_; +}; + +// This class is used to handle relocations against a section symbol +// in an SHF_MERGE section. For such a symbol, we need to know the +// addend of the relocation before we can determine the final value. +// The addend gives us the location in the input section, and we can +// determine how it is mapped to the output section. For a +// non-section symbol, we apply the addend to the final value of the +// symbol; that is done in finalize_local_symbols, and does not use +// this class. + +template +class Merged_symbol_value +{ + public: + typedef typename elfcpp::Elf_types::Elf_Addr Value; + + // We use a hash table to map offsets in the input section to output + // addresses. + typedef Unordered_map Output_addresses; + + Merged_symbol_value(Value input_value, Value output_start_address) + : input_value_(input_value), output_start_address_(output_start_address), + output_addresses_() + { } + + // Initialize the hash table. + void + initialize_input_to_output_map(const Relobj*, unsigned int input_shndx); + + // Release the hash table to save space. + void + free_input_to_output_map() + { this->output_addresses_.clear(); } + + // Get the output value corresponding to an addend. The object and + // input section index are passed in because the caller will have + // them; otherwise we could store them here. + Value + value(const Relobj* object, unsigned int input_shndx, Value addend) const + { + // This is a relocation against a section symbol. ADDEND is the + // offset in the section. The result should be the start of some + // merge area. If the object file wants something else, it should + // use a regular symbol rather than a section symbol. + // Unfortunately, PR 6658 shows a case in which the object file + // refers to the section symbol, but uses a negative ADDEND to + // compensate for a PC relative reloc. We can't handle the + // general case. However, we can handle the special case of a + // negative addend, by assuming that it refers to the start of the + // section. Of course, that means that we have to guess when + // ADDEND is negative. It is normal to see a 32-bit value here + // even when the template parameter size is 64, as 64-bit object + // file formats have 32-bit relocations. We know this is a merge + // section, so we know it has to fit into memory. So we assume + // that we won't see a value larger than a large 32-bit unsigned + // value. This will break objects with very very large merge + // sections; they probably break in other ways anyhow. + Value input_offset = this->input_value_; + if (addend < 0xffffff00) + { + input_offset += addend; + addend = 0; + } + typename Output_addresses::const_iterator p = + this->output_addresses_.find(input_offset); + if (p != this->output_addresses_.end()) + return p->second + addend; + + return (this->value_from_output_section(object, input_shndx, input_offset) + + addend); + } + + private: + // Get the output value for an input offset if we couldn't find it + // in the hash table. + Value + value_from_output_section(const Relobj*, unsigned int input_shndx, + Value input_offset) const; + + // The value of the section symbol in the input file. This is + // normally zero, but could in principle be something else. + Value input_value_; + // The start address of this merged section in the output file. + Value output_start_address_; + // A hash table which maps offsets in the input section to output + // addresses. This only maps specific offsets, not all offsets. + Output_addresses output_addresses_; +}; + +// This POD class is holds the value of a symbol. This is used for +// local symbols, and for all symbols during relocation processing. +// For special sections, such as SHF_MERGE sections, this calls a +// function to get the final symbol value. + +template +class Symbol_value +{ + public: + typedef typename elfcpp::Elf_types::Elf_Addr Value; + + Symbol_value() + : output_symtab_index_(0), output_dynsym_index_(-1U), input_shndx_(0), + is_ordinary_shndx_(false), is_section_symbol_(false), + is_tls_symbol_(false), is_ifunc_symbol_(false), has_output_value_(true) + { this->u_.value = 0; } + + ~Symbol_value() + { + if (!this->has_output_value_) + delete this->u_.merged_symbol_value; + } + + // Get the value of this symbol. OBJECT is the object in which this + // symbol is defined, and ADDEND is an addend to add to the value. + template + Value + value(const Sized_relobj_file* object, Value addend) const + { + if (this->has_output_value_) + return this->u_.value + addend; + else + { + gold_assert(this->is_ordinary_shndx_); + return this->u_.merged_symbol_value->value(object, this->input_shndx_, + addend); + } + } + + // Set the value of this symbol in the output symbol table. + void + set_output_value(Value value) + { this->u_.value = value; } + + // For a section symbol in a merged section, we need more + // information. + void + set_merged_symbol_value(Merged_symbol_value* msv) + { + gold_assert(this->is_section_symbol_); + this->has_output_value_ = false; + this->u_.merged_symbol_value = msv; + } + + // Initialize the input to output map for a section symbol in a + // merged section. We also initialize the value of a non-section + // symbol in a merged section. + void + initialize_input_to_output_map(const Relobj* object) + { + if (!this->has_output_value_) + { + gold_assert(this->is_section_symbol_ && this->is_ordinary_shndx_); + Merged_symbol_value* msv = this->u_.merged_symbol_value; + msv->initialize_input_to_output_map(object, this->input_shndx_); + } + } + + // Free the input to output map for a section symbol in a merged + // section. + void + free_input_to_output_map() + { + if (!this->has_output_value_) + this->u_.merged_symbol_value->free_input_to_output_map(); + } + + // Set the value of the symbol from the input file. This is only + // called by count_local_symbols, to communicate the value to + // finalize_local_symbols. + void + set_input_value(Value value) + { this->u_.value = value; } + + // Return the input value. This is only called by + // finalize_local_symbols and (in special cases) relocate_section. + Value + input_value() const + { return this->u_.value; } + + // Return whether we have set the index in the output symbol table + // yet. + bool + is_output_symtab_index_set() const + { + return (this->output_symtab_index_ != 0 + && this->output_symtab_index_ != -2U); + } + + // Return whether this symbol may be discarded from the normal + // symbol table. + bool + may_be_discarded_from_output_symtab() const + { + gold_assert(!this->is_output_symtab_index_set()); + return this->output_symtab_index_ != -2U; + } + + // Return whether this symbol has an entry in the output symbol + // table. + bool + has_output_symtab_entry() const + { + gold_assert(this->is_output_symtab_index_set()); + return this->output_symtab_index_ != -1U; + } + + // Return the index in the output symbol table. + unsigned int + output_symtab_index() const + { + gold_assert(this->is_output_symtab_index_set() + && this->output_symtab_index_ != -1U); + return this->output_symtab_index_; + } + + // Set the index in the output symbol table. + void + set_output_symtab_index(unsigned int i) + { + gold_assert(!this->is_output_symtab_index_set()); + gold_assert(i != 0 && i != -1U && i != -2U); + this->output_symtab_index_ = i; + } + + // Record that this symbol should not go into the output symbol + // table. + void + set_no_output_symtab_entry() + { + gold_assert(this->output_symtab_index_ == 0); + this->output_symtab_index_ = -1U; + } + + // Record that this symbol must go into the output symbol table, + // because it there is a relocation that uses it. + void + set_must_have_output_symtab_entry() + { + gold_assert(!this->is_output_symtab_index_set()); + this->output_symtab_index_ = -2U; + } + + // Set the index in the output dynamic symbol table. + void + set_needs_output_dynsym_entry() + { + gold_assert(!this->is_section_symbol()); + this->output_dynsym_index_ = 0; + } + + // Return whether this symbol should go into the dynamic symbol + // table. + bool + needs_output_dynsym_entry() const + { + return this->output_dynsym_index_ != -1U; + } + + // Return whether this symbol has an entry in the dynamic symbol + // table. + bool + has_output_dynsym_entry() const + { + gold_assert(this->output_dynsym_index_ != 0); + return this->output_dynsym_index_ != -1U; + } + + // Record that this symbol should go into the dynamic symbol table. + void + set_output_dynsym_index(unsigned int i) + { + gold_assert(this->output_dynsym_index_ == 0); + gold_assert(i != 0 && i != -1U); + this->output_dynsym_index_ = i; + } + + // Return the index in the output dynamic symbol table. + unsigned int + output_dynsym_index() const + { + gold_assert(this->output_dynsym_index_ != 0 + && this->output_dynsym_index_ != -1U); + return this->output_dynsym_index_; + } + + // Set the index of the input section in the input file. + void + set_input_shndx(unsigned int i, bool is_ordinary) + { + this->input_shndx_ = i; + // input_shndx_ field is a bitfield, so make sure that the value + // fits. + gold_assert(this->input_shndx_ == i); + this->is_ordinary_shndx_ = is_ordinary; + } + + // Return the index of the input section in the input file. + unsigned int + input_shndx(bool* is_ordinary) const + { + *is_ordinary = this->is_ordinary_shndx_; + return this->input_shndx_; + } + + // Whether this is a section symbol. + bool + is_section_symbol() const + { return this->is_section_symbol_; } + + // Record that this is a section symbol. + void + set_is_section_symbol() + { + gold_assert(!this->needs_output_dynsym_entry()); + this->is_section_symbol_ = true; + } + + // Record that this is a TLS symbol. + void + set_is_tls_symbol() + { this->is_tls_symbol_ = true; } + + // Return true if this is a TLS symbol. + bool + is_tls_symbol() const + { return this->is_tls_symbol_; } + + // Record that this is an IFUNC symbol. + void + set_is_ifunc_symbol() + { this->is_ifunc_symbol_ = true; } + + // Return true if this is an IFUNC symbol. + bool + is_ifunc_symbol() const + { return this->is_ifunc_symbol_; } + + // Return true if this has output value. + bool + has_output_value() const + { return this->has_output_value_; } + + private: + // The index of this local symbol in the output symbol table. This + // will be 0 if no value has been assigned yet, and the symbol may + // be omitted. This will be -1U if the symbol should not go into + // the symbol table. This will be -2U if the symbol must go into + // the symbol table, but no index has been assigned yet. + unsigned int output_symtab_index_; + // The index of this local symbol in the dynamic symbol table. This + // will be -1U if the symbol should not go into the symbol table. + unsigned int output_dynsym_index_; + // The section index in the input file in which this symbol is + // defined. + unsigned int input_shndx_ : 27; + // Whether the section index is an ordinary index, not a special + // value. + bool is_ordinary_shndx_ : 1; + // Whether this is a STT_SECTION symbol. + bool is_section_symbol_ : 1; + // Whether this is a STT_TLS symbol. + bool is_tls_symbol_ : 1; + // Whether this is a STT_GNU_IFUNC symbol. + bool is_ifunc_symbol_ : 1; + // Whether this symbol has a value for the output file. This is + // normally set to true during Layout::finalize, by + // finalize_local_symbols. It will be false for a section symbol in + // a merge section, as for such symbols we can not determine the + // value to use in a relocation until we see the addend. + bool has_output_value_ : 1; + union + { + // This is used if has_output_value_ is true. Between + // count_local_symbols and finalize_local_symbols, this is the + // value in the input file. After finalize_local_symbols, it is + // the value in the output file. + Value value; + // This is used if has_output_value_ is false. It points to the + // information we need to get the value for a merge section. + Merged_symbol_value* merged_symbol_value; + } u_; +}; + +// This type is used to modify relocations for -fsplit-stack. It is +// indexed by relocation index, and means that the relocation at that +// index should use the symbol from the vector, rather than the one +// indicated by the relocation. + +class Reloc_symbol_changes +{ + public: + Reloc_symbol_changes(size_t count) + : vec_(count, NULL) + { } + + void + set(size_t i, Symbol* sym) + { this->vec_[i] = sym; } + + const Symbol* + operator[](size_t i) const + { return this->vec_[i]; } + + private: + std::vector vec_; +}; + +// Type for mapping section index to uncompressed size and contents. + +struct Compressed_section_info +{ + section_size_type size; + const unsigned char* contents; +}; +typedef std::map Compressed_section_map; + +// Abstract base class for a regular object file, either a real object file +// or an incremental (unchanged) object. This is size and endian specific. + +template +class Sized_relobj : public Relobj +{ + public: + typedef typename elfcpp::Elf_types::Elf_Addr Address; + typedef Relobj::Symbols Symbols; + + static const Address invalid_address = static_cast
(0) - 1; + + Sized_relobj(const std::string& name, Input_file* input_file) + : Relobj(name, input_file), local_got_offsets_(), section_offsets_() + { } + + Sized_relobj(const std::string& name, Input_file* input_file, + off_t offset) + : Relobj(name, input_file, offset), local_got_offsets_(), section_offsets_() + { } + + ~Sized_relobj() + { } + + // If this is a regular object, return a pointer to the Sized_relobj_file + // object. Otherwise, return NULL. + virtual Sized_relobj_file* + sized_relobj() + { return NULL; } + + const virtual Sized_relobj_file* + sized_relobj() const + { return NULL; } + + // Checks if the offset of input section SHNDX within its output + // section is invalid. + bool + is_output_section_offset_invalid(unsigned int shndx) const + { return this->get_output_section_offset(shndx) == invalid_address; } + + // Get the offset of input section SHNDX within its output section. + // This is -1 if the input section requires a special mapping, such + // as a merge section. The output section can be found in the + // output_sections_ field of the parent class Relobj. + Address + get_output_section_offset(unsigned int shndx) const + { + gold_assert(shndx < this->section_offsets_.size()); + return this->section_offsets_[shndx]; + } + + // Iterate over local symbols, calling a visitor class V for each GOT offset + // associated with a local symbol. + void + do_for_all_local_got_entries(Got_offset_list::Visitor* v) const; + + protected: + typedef Relobj::Output_sections Output_sections; + + // Clear the local symbol information. + void + clear_got_offsets() + { this->local_got_offsets_.clear(); } + + // Return the vector of section offsets. + std::vector
& + section_offsets() + { return this->section_offsets_; } + + // Get the address of an output section. + uint64_t + do_output_section_address(unsigned int shndx); + + // Get the offset of a section. + uint64_t + do_output_section_offset(unsigned int shndx) const + { + Address off = this->get_output_section_offset(shndx); + if (off == invalid_address) + return -1ULL; + return off; + } + + // Set the offset of a section. + void + do_set_section_offset(unsigned int shndx, uint64_t off) + { + gold_assert(shndx < this->section_offsets_.size()); + this->section_offsets_[shndx] = + (off == static_cast(-1) + ? invalid_address + : convert_types(off)); + } + + // Return whether the local symbol SYMNDX has a GOT offset of type + // GOT_TYPE. + bool + do_local_has_got_offset(unsigned int symndx, unsigned int got_type) const + { + Local_got_offsets::const_iterator p = + this->local_got_offsets_.find(symndx); + return (p != this->local_got_offsets_.end() + && p->second->get_offset(got_type) != -1U); + } + + // Return the GOT offset of type GOT_TYPE of the local symbol + // SYMNDX. + unsigned int + do_local_got_offset(unsigned int symndx, unsigned int got_type) const + { + Local_got_offsets::const_iterator p = + this->local_got_offsets_.find(symndx); + gold_assert(p != this->local_got_offsets_.end()); + unsigned int off = p->second->get_offset(got_type); + gold_assert(off != -1U); + return off; + } + + // Set the GOT offset with type GOT_TYPE of the local symbol SYMNDX + // to GOT_OFFSET. + void + do_set_local_got_offset(unsigned int symndx, unsigned int got_type, + unsigned int got_offset) + { + Local_got_offsets::const_iterator p = + this->local_got_offsets_.find(symndx); + if (p != this->local_got_offsets_.end()) + p->second->set_offset(got_type, got_offset); + else + { + Got_offset_list* g = new Got_offset_list(got_type, got_offset); + std::pair ins = + this->local_got_offsets_.insert(std::make_pair(symndx, g)); + gold_assert(ins.second); + } + } + + // Return the word size of the object file. + virtual int + do_elfsize() const + { return size; } + + // Return TRUE if this is a big-endian object file. + virtual bool + do_is_big_endian() const + { return big_endian; } + + private: + // The GOT offsets of local symbols. This map also stores GOT offsets + // for tp-relative offsets for TLS symbols. + typedef Unordered_map Local_got_offsets; + + // GOT offsets for local non-TLS symbols, and tp-relative offsets + // for TLS symbols, indexed by symbol number. + Local_got_offsets local_got_offsets_; + // For each input section, the offset of the input section in its + // output section. This is INVALID_ADDRESS if the input section requires a + // special mapping. + std::vector
section_offsets_; +}; + +// A regular object file. This is size and endian specific. + +template +class Sized_relobj_file : public Sized_relobj +{ + public: + typedef typename elfcpp::Elf_types::Elf_Addr Address; + typedef typename Sized_relobj::Symbols Symbols; + typedef std::vector > Local_values; + + static const Address invalid_address = static_cast
(0) - 1; + + enum Compute_final_local_value_status + { + // No error. + CFLV_OK, + // An error occurred. + CFLV_ERROR, + // The local symbol has no output section. + CFLV_DISCARDED + }; + + Sized_relobj_file(const std::string& name, + Input_file* input_file, + off_t offset, + const typename elfcpp::Ehdr&); + + ~Sized_relobj_file(); + + // Set up the object file based on TARGET. + void + setup() + { this->do_setup(); } + + // Return a pointer to the Sized_relobj_file object. + Sized_relobj_file* + sized_relobj() + { return this; } + + const Sized_relobj_file* + sized_relobj() const + { return this; } + + // Return the ELF file type. + int + e_type() const + { return this->e_type_; } + + // Return the number of symbols. This is only valid after + // Object::add_symbols has been called. + unsigned int + symbol_count() const + { return this->local_symbol_count_ + this->symbols_.size(); } + + // If SYM is the index of a global symbol in the object file's + // symbol table, return the Symbol object. Otherwise, return NULL. + Symbol* + global_symbol(unsigned int sym) const + { + if (sym >= this->local_symbol_count_) + { + gold_assert(sym - this->local_symbol_count_ < this->symbols_.size()); + return this->symbols_[sym - this->local_symbol_count_]; + } + return NULL; + } + + // Return the section index of symbol SYM. Set *VALUE to its value + // in the object file. Set *IS_ORDINARY if this is an ordinary + // section index, not a special code between SHN_LORESERVE and + // SHN_HIRESERVE. Note that for a symbol which is not defined in + // this object file, this will set *VALUE to 0 and return SHN_UNDEF; + // it will not return the final value of the symbol in the link. + unsigned int + symbol_section_and_value(unsigned int sym, Address* value, bool* is_ordinary); + + // Return a pointer to the Symbol_value structure which holds the + // value of a local symbol. + const Symbol_value* + local_symbol(unsigned int sym) const + { + gold_assert(sym < this->local_values_.size()); + return &this->local_values_[sym]; + } + + // Return the index of local symbol SYM in the ordinary symbol + // table. A value of -1U means that the symbol is not being output. + unsigned int + symtab_index(unsigned int sym) const + { + gold_assert(sym < this->local_values_.size()); + return this->local_values_[sym].output_symtab_index(); + } + + // Return the index of local symbol SYM in the dynamic symbol + // table. A value of -1U means that the symbol is not being output. + unsigned int + dynsym_index(unsigned int sym) const + { + gold_assert(sym < this->local_values_.size()); + return this->local_values_[sym].output_dynsym_index(); + } + + // Return the input section index of local symbol SYM. + unsigned int + local_symbol_input_shndx(unsigned int sym, bool* is_ordinary) const + { + gold_assert(sym < this->local_values_.size()); + return this->local_values_[sym].input_shndx(is_ordinary); + } + + // Record that local symbol SYM must be in the output symbol table. + void + set_must_have_output_symtab_entry(unsigned int sym) + { + gold_assert(sym < this->local_values_.size()); + this->local_values_[sym].set_must_have_output_symtab_entry(); + } + + // Record that local symbol SYM needs a dynamic symbol entry. + void + set_needs_output_dynsym_entry(unsigned int sym) + { + gold_assert(sym < this->local_values_.size()); + this->local_values_[sym].set_needs_output_dynsym_entry(); + } + + // Return whether the local symbol SYMNDX has a PLT offset. + bool + local_has_plt_offset(unsigned int symndx) const; + + // Set the PLT offset of the local symbol SYMNDX. + void + set_local_plt_offset(unsigned int symndx, unsigned int plt_offset); + + // Adjust this local symbol value. Return false if the symbol + // should be discarded from the output file. + bool + adjust_local_symbol(Symbol_value* lv) const + { return this->do_adjust_local_symbol(lv); } + + // Return the name of the symbol that spans the given offset in the + // specified section in this object. This is used only for error + // messages and is not particularly efficient. + bool + get_symbol_location_info(unsigned int shndx, off_t offset, + Symbol_location_info* info); + + // Look for a kept section corresponding to the given discarded section, + // and return its output address. This is used only for relocations in + // debugging sections. + Address + map_to_kept_section(unsigned int shndx, bool* found) const; + + // Compute final local symbol value. R_SYM is the local symbol index. + // LV_IN points to a local symbol value containing the input value. + // LV_OUT points to a local symbol value storing the final output value, + // which must not be a merged symbol value since before calling this + // method to avoid memory leak. SYMTAB points to a symbol table. + // + // The method returns a status code at return. If the return status is + // CFLV_OK, *LV_OUT contains the final value. If the return status is + // CFLV_ERROR, *LV_OUT is 0. If the return status is CFLV_DISCARDED, + // *LV_OUT is not modified. + Compute_final_local_value_status + compute_final_local_value(unsigned int r_sym, + const Symbol_value* lv_in, + Symbol_value* lv_out, + const Symbol_table* symtab); + + protected: + typedef typename Sized_relobj::Output_sections + Output_sections; + + // Set up. + virtual void + do_setup(); + + // Read the symbols. + void + do_read_symbols(Read_symbols_data*); + + // Return the value of a local symbol. + uint64_t + do_local_symbol_value(unsigned int symndx, uint64_t addend) const + { + const Symbol_value* symval = this->local_symbol(symndx); + return symval->value(this, addend); + } + + // Return the PLT offset for a local symbol. It is an error to call + // this if it doesn't have one. + unsigned int + do_local_plt_offset(unsigned int symndx) const; + + // Return whether local symbol SYMNDX is a TLS symbol. + bool + do_local_is_tls(unsigned int symndx) const + { return this->local_symbol(symndx)->is_tls_symbol(); } + + // Return the number of local symbols. + unsigned int + do_local_symbol_count() const + { return this->local_symbol_count_; } + + // Return the number of local symbols in the output symbol table. + unsigned int + do_output_local_symbol_count() const + { return this->output_local_symbol_count_; } + + // Return the number of local symbols in the output symbol table. + off_t + do_local_symbol_offset() const + { return this->local_symbol_offset_; } + + // Lay out the input sections. + void + do_layout(Symbol_table*, Layout*, Read_symbols_data*); + + // Layout sections whose layout was deferred while waiting for + // input files from a plugin. + void + do_layout_deferred_sections(Layout*); + + // Add the symbols to the symbol table. + void + do_add_symbols(Symbol_table*, Read_symbols_data*, Layout*); + + Archive::Should_include + do_should_include_member(Symbol_table* symtab, Layout*, Read_symbols_data*, + std::string* why); + + // Iterate over global symbols, calling a visitor class V for each. + void + do_for_all_global_symbols(Read_symbols_data* sd, + Library_base::Symbol_visitor_base* v); + + // Read the relocs. + void + do_read_relocs(Read_relocs_data*); + + // Process the relocs to find list of referenced sections. Used only + // during garbage collection. + void + do_gc_process_relocs(Symbol_table*, Layout*, Read_relocs_data*); + + // Scan the relocs and adjust the symbol table. + void + do_scan_relocs(Symbol_table*, Layout*, Read_relocs_data*); + + // Count the local symbols. + void + do_count_local_symbols(Stringpool_template*, + Stringpool_template*); + + // Finalize the local symbols. + unsigned int + do_finalize_local_symbols(unsigned int, off_t, Symbol_table*); + + // Set the offset where local dynamic symbol information will be stored. + unsigned int + do_set_local_dynsym_indexes(unsigned int); + + // Set the offset where local dynamic symbol information will be stored. + unsigned int + do_set_local_dynsym_offset(off_t); + + // Relocate the input sections and write out the local symbols. + void + do_relocate(const Symbol_table* symtab, const Layout*, Output_file* of); + + // Get the size of a section. + uint64_t + do_section_size(unsigned int shndx) + { return this->elf_file_.section_size(shndx); } + + // Get the name of a section. + std::string + do_section_name(unsigned int shndx) + { return this->elf_file_.section_name(shndx); } + + // Return the location of the contents of a section. + const unsigned char* + do_section_contents(unsigned int shndx, section_size_type* plen, + bool cache) + { + Object::Location loc(this->elf_file_.section_contents(shndx)); + *plen = convert_to_section_size_type(loc.data_size); + if (*plen == 0) + { + static const unsigned char empty[1] = { '\0' }; + return empty; + } + return this->get_view(loc.file_offset, *plen, true, cache); + } + + // Return section flags. + uint64_t + do_section_flags(unsigned int shndx); + + // Return section entsize. + uint64_t + do_section_entsize(unsigned int shndx); + + // Return section address. + uint64_t + do_section_address(unsigned int shndx) + { return this->elf_file_.section_addr(shndx); } + + // Return section type. + unsigned int + do_section_type(unsigned int shndx) + { return this->elf_file_.section_type(shndx); } + + // Return the section link field. + unsigned int + do_section_link(unsigned int shndx) + { return this->elf_file_.section_link(shndx); } + + // Return the section info field. + unsigned int + do_section_info(unsigned int shndx) + { return this->elf_file_.section_info(shndx); } + + // Return the section alignment. + uint64_t + do_section_addralign(unsigned int shndx) + { return this->elf_file_.section_addralign(shndx); } + + // Return the Xindex structure to use. + Xindex* + do_initialize_xindex(); + + // Get symbol counts. + void + do_get_global_symbol_counts(const Symbol_table*, size_t*, size_t*) const; + + // Get the global symbols. + const Symbols* + do_get_global_symbols() const + { return &this->symbols_; } + + // Adjust a section index if necessary. + unsigned int + adjust_shndx(unsigned int shndx) + { + if (shndx >= elfcpp::SHN_LORESERVE) + shndx += this->elf_file_.large_shndx_offset(); + return shndx; + } + + // Initialize input to output maps for section symbols in merged + // sections. + void + initialize_input_to_output_maps(); + + // Free the input to output maps for section symbols in merged + // sections. + void + free_input_to_output_maps(); + + // Return symbol table section index. + unsigned int + symtab_shndx() const + { return this->symtab_shndx_; } + + // Allow a child class to access the ELF file. + elfcpp::Elf_file* + elf_file() + { return &this->elf_file_; } + + // Allow a child class to access the local values. + Local_values* + local_values() + { return &this->local_values_; } + + // Views and sizes when relocating. + struct View_size + { + unsigned char* view; + typename elfcpp::Elf_types::Elf_Addr address; + off_t offset; + section_size_type view_size; + bool is_input_output_view; + bool is_postprocessing_view; + bool is_ctors_reverse_view; + }; + + typedef std::vector Views; + + // Stash away info for a number of special sections. + // Return true if any of the sections found require local symbols to be read. + virtual bool + do_find_special_sections(Read_symbols_data* sd); + + // This may be overriden by a child class. + virtual void + do_relocate_sections(const Symbol_table* symtab, const Layout* layout, + const unsigned char* pshdrs, Output_file* of, + Views* pviews); + + // Adjust this local symbol value. Return false if the symbol + // should be discarded from the output file. + virtual bool + do_adjust_local_symbol(Symbol_value*) const + { return true; } + + // Allow a child to set output local symbol count. + void + set_output_local_symbol_count(unsigned int value) + { this->output_local_symbol_count_ = value; } + + // Return TRUE if the section is a compressed debug section, and set + // *UNCOMPRESSED_SIZE to the size of the uncompressed data. + bool + do_section_is_compressed(unsigned int shndx, + section_size_type* uncompressed_size) const + { + if (this->compressed_sections_ == NULL) + return false; + Compressed_section_map::const_iterator p = + this->compressed_sections_->find(shndx); + if (p != this->compressed_sections_->end()) + { + if (uncompressed_size != NULL) + *uncompressed_size = p->second.size; + return true; + } + return false; + } + + // Return a view of the uncompressed contents of a section. Set *PLEN + // to the size. Set *IS_NEW to true if the contents need to be deleted + // by the caller. + const unsigned char* + do_decompressed_section_contents(unsigned int shndx, + section_size_type* plen, + bool* is_new); + + // Discard any buffers of decompressed sections. This is done + // at the end of the Add_symbols task. + void + do_discard_decompressed_sections(); + + private: + // For convenience. + typedef Sized_relobj_file This; + static const int ehdr_size = elfcpp::Elf_sizes::ehdr_size; + static const int shdr_size = elfcpp::Elf_sizes::shdr_size; + static const int sym_size = elfcpp::Elf_sizes::sym_size; + typedef elfcpp::Shdr Shdr; + + // To keep track of discarded comdat sections, we need to map a member + // section index to the object and section index of the corresponding + // kept section. + struct Kept_comdat_section + { + Kept_comdat_section(Relobj* a_object, unsigned int a_shndx) + : object(a_object), shndx(a_shndx) + { } + Relobj* object; + unsigned int shndx; + }; + typedef std::map + Kept_comdat_section_table; + + // Find the SHT_SYMTAB section, given the section headers. + void + find_symtab(const unsigned char* pshdrs); + + // Return whether SHDR has the right flags for a GNU style exception + // frame section. + bool + check_eh_frame_flags(const elfcpp::Shdr* shdr) const; + + // Return whether there is a section named .eh_frame which might be + // a GNU style exception frame section. + bool + find_eh_frame(const unsigned char* pshdrs, const char* names, + section_size_type names_size) const; + + // Whether to include a section group in the link. + bool + include_section_group(Symbol_table*, Layout*, unsigned int, const char*, + const unsigned char*, const char*, section_size_type, + std::vector*); + + // Whether to include a linkonce section in the link. + bool + include_linkonce_section(Layout*, unsigned int, const char*, + const elfcpp::Shdr&); + + // Layout an input section. + void + layout_section(Layout* layout, unsigned int shndx, const char* name, + const typename This::Shdr& shdr, unsigned int reloc_shndx, + unsigned int reloc_type); + + // Layout an input .eh_frame section. + void + layout_eh_frame_section(Layout* layout, const unsigned char* symbols_data, + section_size_type symbols_size, + const unsigned char* symbol_names_data, + section_size_type symbol_names_size, + unsigned int shndx, const typename This::Shdr&, + unsigned int reloc_shndx, unsigned int reloc_type); + + // Write section data to the output file. Record the views and + // sizes in VIEWS for use when relocating. + void + write_sections(const Layout*, const unsigned char* pshdrs, Output_file*, + Views*); + + // Relocate the sections in the output file. + void + relocate_sections(const Symbol_table* symtab, const Layout* layout, + const unsigned char* pshdrs, Output_file* of, + Views* pviews) + { this->do_relocate_sections(symtab, layout, pshdrs, of, pviews); } + + // Reverse the words in a section. Used for .ctors sections mapped + // to .init_array sections. + void + reverse_words(unsigned char*, section_size_type); + + // Scan the input relocations for --emit-relocs. + void + emit_relocs_scan(Symbol_table*, Layout*, const unsigned char* plocal_syms, + const Read_relocs_data::Relocs_list::iterator&); + + // Scan the input relocations for --emit-relocs, templatized on the + // type of the relocation section. + template + void + emit_relocs_scan_reltype(Symbol_table*, Layout*, + const unsigned char* plocal_syms, + const Read_relocs_data::Relocs_list::iterator&, + Relocatable_relocs*); + + // Scan the input relocations for --incremental. + void + incremental_relocs_scan(const Read_relocs_data::Relocs_list::iterator&); + + // Scan the input relocations for --incremental, templatized on the + // type of the relocation section. + template + void + incremental_relocs_scan_reltype( + const Read_relocs_data::Relocs_list::iterator&); + + void + incremental_relocs_write(const Relocate_info*, + unsigned int sh_type, + const unsigned char* prelocs, + size_t reloc_count, + Output_section*, + Address output_offset, + Output_file*); + + template + void + incremental_relocs_write_reltype(const Relocate_info*, + const unsigned char* prelocs, + size_t reloc_count, + Output_section*, + Address output_offset, + Output_file*); + + // A type shared by split_stack_adjust_reltype and find_functions. + typedef std::map Function_offsets; + + // Check for -fsplit-stack routines calling non-split-stack routines. + void + split_stack_adjust(const Symbol_table*, const unsigned char* pshdrs, + unsigned int sh_type, unsigned int shndx, + const unsigned char* prelocs, size_t reloc_count, + unsigned char* view, section_size_type view_size, + Reloc_symbol_changes** reloc_map); + + template + void + split_stack_adjust_reltype(const Symbol_table*, const unsigned char* pshdrs, + unsigned int shndx, const unsigned char* prelocs, + size_t reloc_count, unsigned char* view, + section_size_type view_size, + Reloc_symbol_changes** reloc_map); + + // Find all functions in a section. + void + find_functions(const unsigned char* pshdrs, unsigned int shndx, + Function_offsets*); + + // Write out the local symbols. + void + write_local_symbols(Output_file*, + const Stringpool_template*, + const Stringpool_template*, + Output_symtab_xindex*, + Output_symtab_xindex*, + off_t); + + // Record a mapping from discarded section SHNDX to the corresponding + // kept section. + void + set_kept_comdat_section(unsigned int shndx, Relobj* kept_object, + unsigned int kept_shndx) + { + Kept_comdat_section kept(kept_object, kept_shndx); + this->kept_comdat_sections_.insert(std::make_pair(shndx, kept)); + } + + // Find the kept section corresponding to the discarded section + // SHNDX. Return true if found. + bool + get_kept_comdat_section(unsigned int shndx, Relobj** kept_object, + unsigned int* kept_shndx) const + { + typename Kept_comdat_section_table::const_iterator p = + this->kept_comdat_sections_.find(shndx); + if (p == this->kept_comdat_sections_.end()) + return false; + *kept_object = p->second.object; + *kept_shndx = p->second.shndx; + return true; + } + + // Compute final local symbol value. R_SYM is the local symbol index. + // LV_IN points to a local symbol value containing the input value. + // LV_OUT points to a local symbol value storing the final output value, + // which must not be a merged symbol value since before calling this + // method to avoid memory leak. RELOCATABLE indicates whether we are + // linking a relocatable output. OUT_SECTIONS is an array of output + // sections. OUT_OFFSETS is an array of offsets of the sections. SYMTAB + // points to a symbol table. + // + // The method returns a status code at return. If the return status is + // CFLV_OK, *LV_OUT contains the final value. If the return status is + // CFLV_ERROR, *LV_OUT is 0. If the return status is CFLV_DISCARDED, + // *LV_OUT is not modified. + inline Compute_final_local_value_status + compute_final_local_value_internal(unsigned int r_sym, + const Symbol_value* lv_in, + Symbol_value* lv_out, + bool relocatable, + const Output_sections& out_sections, + const std::vector
& out_offsets, + const Symbol_table* symtab); + + // The PLT offsets of local symbols. + typedef Unordered_map Local_plt_offsets; + + // Saved information for sections whose layout was deferred. + struct Deferred_layout + { + static const int shdr_size = elfcpp::Elf_sizes::shdr_size; + Deferred_layout(unsigned int shndx, const char* name, + const unsigned char* pshdr, + unsigned int reloc_shndx, unsigned int reloc_type) + : shndx_(shndx), name_(name), reloc_shndx_(reloc_shndx), + reloc_type_(reloc_type) + { + memcpy(this->shdr_data_, pshdr, shdr_size); + } + unsigned int shndx_; + std::string name_; + unsigned int reloc_shndx_; + unsigned int reloc_type_; + unsigned char shdr_data_[shdr_size]; + }; + + // General access to the ELF file. + elfcpp::Elf_file elf_file_; + // Type of ELF file (ET_REL or ET_EXEC). ET_EXEC files are allowed + // as input files only for the --just-symbols option. + int e_type_; + // Index of SHT_SYMTAB section. + unsigned int symtab_shndx_; + // The number of local symbols. + unsigned int local_symbol_count_; + // The number of local symbols which go into the output file. + unsigned int output_local_symbol_count_; + // The number of local symbols which go into the output file's dynamic + // symbol table. + unsigned int output_local_dynsym_count_; + // The entries in the symbol table for the external symbols. + Symbols symbols_; + // Number of symbols defined in object file itself. + size_t defined_count_; + // File offset for local symbols (relative to start of symbol table). + off_t local_symbol_offset_; + // File offset for local dynamic symbols (absolute). + off_t local_dynsym_offset_; + // Values of local symbols. + Local_values local_values_; + // PLT offsets for local symbols. + Local_plt_offsets local_plt_offsets_; + // Table mapping discarded comdat sections to corresponding kept sections. + Kept_comdat_section_table kept_comdat_sections_; + // Whether this object has a GNU style .eh_frame section. + bool has_eh_frame_; + // If this object has a GNU style .eh_frame section that is discarded in + // output, record the index here. Otherwise it is -1U. + unsigned int discarded_eh_frame_shndx_; + // The list of sections whose layout was deferred. + std::vector deferred_layout_; + // The list of relocation sections whose layout was deferred. + std::vector deferred_layout_relocs_; + // For compressed debug sections, map section index to uncompressed size + // and contents. + Compressed_section_map* compressed_sections_; +}; + +// A class to manage the list of all objects. + +class Input_objects +{ + public: + Input_objects() + : relobj_list_(), dynobj_list_(), sonames_(), cref_(NULL) + { } + + // The type of the list of input relocateable objects. + typedef std::vector Relobj_list; + typedef Relobj_list::const_iterator Relobj_iterator; + + // The type of the list of input dynamic objects. + typedef std::vector Dynobj_list; + typedef Dynobj_list::const_iterator Dynobj_iterator; + + // Add an object to the list. Return true if all is well, or false + // if this object should be ignored. + bool + add_object(Object*); + + // Start processing an archive. + void + archive_start(Archive*); + + // Stop processing an archive. + void + archive_stop(Archive*); + + // For each dynamic object, check whether we've seen all of its + // explicit dependencies. + void + check_dynamic_dependencies() const; + + // Return whether an object was found in the system library + // directory. + bool + found_in_system_library_directory(const Object*) const; + + // Print symbol counts. + void + print_symbol_counts(const Symbol_table*) const; + + // Print a cross reference table. + void + print_cref(const Symbol_table*, FILE*) const; + + // Iterate over all regular objects. + + Relobj_iterator + relobj_begin() const + { return this->relobj_list_.begin(); } + + Relobj_iterator + relobj_end() const + { return this->relobj_list_.end(); } + + // Iterate over all dynamic objects. + + Dynobj_iterator + dynobj_begin() const + { return this->dynobj_list_.begin(); } + + Dynobj_iterator + dynobj_end() const + { return this->dynobj_list_.end(); } + + // Return whether we have seen any dynamic objects. + bool + any_dynamic() const + { return !this->dynobj_list_.empty(); } + + // Return the number of non dynamic objects. + int + number_of_relobjs() const + { return this->relobj_list_.size(); } + + // Return the number of input objects. + int + number_of_input_objects() const + { return this->relobj_list_.size() + this->dynobj_list_.size(); } + + private: + Input_objects(const Input_objects&); + Input_objects& operator=(const Input_objects&); + + // The list of ordinary objects included in the link. + Relobj_list relobj_list_; + // The list of dynamic objects included in the link. + Dynobj_list dynobj_list_; + // SONAMEs that we have seen. + Unordered_set sonames_; + // Manage cross-references if requested. + Cref* cref_; +}; + +// Some of the information we pass to the relocation routines. We +// group this together to avoid passing a dozen different arguments. + +template +struct Relocate_info +{ + // Symbol table. + const Symbol_table* symtab; + // Layout. + const Layout* layout; + // Object being relocated. + Sized_relobj_file* object; + // Section index of relocation section. + unsigned int reloc_shndx; + // Section header of relocation section. + const unsigned char* reloc_shdr; + // Section index of section being relocated. + unsigned int data_shndx; + // Section header of data section. + const unsigned char* data_shdr; + + // Return a string showing the location of a relocation. This is + // only used for error messages. + std::string + location(size_t relnum, off_t reloffset) const; +}; + +// This is used to represent a section in an object and is used as the +// key type for various section maps. +typedef std::pair Section_id; + +// This is similar to Section_id but is used when the section +// pointers are const. +typedef std::pair Const_section_id; + +// The hash value is based on the address of an object in memory during +// linking. It is okay to use this for looking up sections but never use +// this in an unordered container that we want to traverse in a repeatable +// manner. + +struct Section_id_hash +{ + size_t operator()(const Section_id& loc) const + { return reinterpret_cast(loc.first) ^ loc.second; } +}; + +struct Const_section_id_hash +{ + size_t operator()(const Const_section_id& loc) const + { return reinterpret_cast(loc.first) ^ loc.second; } +}; + +// Return whether INPUT_FILE contains an ELF object start at file +// offset OFFSET. This sets *START to point to a view of the start of +// the file. It sets *READ_SIZE to the number of bytes in the view. + +extern bool +is_elf_object(Input_file* input_file, off_t offset, + const unsigned char** start, int* read_size); + +// Return an Object appropriate for the input file. P is BYTES long, +// and holds the ELF header. If PUNCONFIGURED is not NULL, then if +// this sees an object the linker is not configured to support, it +// sets *PUNCONFIGURED to true and returns NULL without giving an +// error message. + +extern Object* +make_elf_object(const std::string& name, Input_file*, + off_t offset, const unsigned char* p, + section_offset_type bytes, bool* punconfigured); + +} // end namespace gold + +#endif // !defined(GOLD_OBJECT_H) diff --git a/binutils-2.25/gold/options.cc b/binutils-2.25/gold/options.cc new file mode 100644 index 00000000..000e6d07 --- /dev/null +++ b/binutils-2.25/gold/options.cc @@ -0,0 +1,1499 @@ +// options.c -- handle command line options for gold + +// Copyright 2006, 2007, 2008, 2009, 2010, 2011, 2013 +// Free Software Foundation, Inc. +// Written by Ian Lance Taylor . + +// 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 +#include +#include +#include +#include +#include +#include +#include "filenames.h" +#include "libiberty.h" +#include "demangle.h" +#include "../bfd/bfdver.h" + +#include "debug.h" +#include "script.h" +#include "target-select.h" +#include "options.h" +#include "plugin.h" + +namespace gold +{ + +General_options +Position_dependent_options::default_options_; + +namespace options +{ + +// This flag is TRUE if we should register the command-line options as they +// are constructed. It is set after construction of the options within +// class Position_dependent_options. +static bool ready_to_register = false; + +// This global variable is set up as General_options is constructed. +static std::vector registered_options; + +// These are set up at the same time -- the variables that accept one +// dash, two, or require -z. A single variable may be in more than +// one of these data structures. +typedef Unordered_map Option_map; +static Option_map* long_options = NULL; +static One_option* short_options[128]; + +void +One_option::register_option() +{ + if (!ready_to_register) + return; + + registered_options.push_back(this); + + // We can't make long_options a static Option_map because we can't + // guarantee that will be initialized before register_option() is + // first called. + if (long_options == NULL) + long_options = new Option_map; + + // TWO_DASHES means that two dashes are preferred, but one is ok too. + if (!this->longname.empty()) + (*long_options)[this->longname] = this; + + const int shortname_as_int = static_cast(this->shortname); + gold_assert(shortname_as_int >= 0 && shortname_as_int < 128); + if (this->shortname != '\0') + { + gold_assert(short_options[shortname_as_int] == NULL); + short_options[shortname_as_int] = this; + } +} + +void +One_option::print() const +{ + bool comma = false; + printf(" "); + int len = 2; + if (this->shortname != '\0') + { + len += printf("-%c", this->shortname); + if (this->helparg) + { + // -z takes long-names only. + gold_assert(this->dashes != DASH_Z); + len += printf(" %s", gettext(this->helparg)); + } + comma = true; + } + if (!this->longname.empty() + && !(this->longname[0] == this->shortname + && this->longname[1] == '\0')) + { + if (comma) + len += printf(", "); + switch (this->dashes) + { + case options::ONE_DASH: case options::EXACTLY_ONE_DASH: + len += printf("-"); + break; + case options::TWO_DASHES: case options::EXACTLY_TWO_DASHES: + len += printf("--"); + break; + case options::DASH_Z: + len += printf("-z "); + break; + default: + gold_unreachable(); + } + len += printf("%s", this->longname.c_str()); + if (this->helparg) + { + // For most options, we print "--frob FOO". But for -z + // we print "-z frob=FOO". + len += printf("%c%s", this->dashes == options::DASH_Z ? '=' : ' ', + gettext(this->helparg)); + } + } + + if (len >= 30) + { + printf("\n"); + len = 0; + } + for (; len < 30; ++len) + std::putchar(' '); + + // TODO: if we're boolean, add " (default)" when appropriate. + printf("%s\n", gettext(this->helpstring)); +} + +void +help() +{ + printf(_("Usage: %s [options] file...\nOptions:\n"), gold::program_name); + + std::vector::const_iterator it; + for (it = registered_options.begin(); it != registered_options.end(); ++it) + (*it)->print(); + + // config.guess and libtool.m4 look in ld --help output for the + // string "supported targets". + printf(_("%s: supported targets:"), gold::program_name); + std::vector supported_names; + gold::supported_target_names(&supported_names); + for (std::vector::const_iterator p = supported_names.begin(); + p != supported_names.end(); + ++p) + printf(" %s", *p); + printf("\n"); + + printf(_("%s: supported emulations:"), gold::program_name); + supported_names.clear(); + gold::supported_emulation_names(&supported_names); + for (std::vector::const_iterator p = supported_names.begin(); + p != supported_names.end(); + ++p) + printf(" %s", *p); + printf("\n"); + + // REPORT_BUGS_TO is defined in bfd/bfdver.h. + const char* report = REPORT_BUGS_TO; + if (*report != '\0') + printf(_("Report bugs to %s\n"), report); +} + +// For bool, arg will be NULL (boolean options take no argument); +// we always just set to true. +void +parse_bool(const char*, const char*, bool* retval) +{ + *retval = true; +} + +void +parse_uint(const char* option_name, const char* arg, int* retval) +{ + char* endptr; + *retval = strtol(arg, &endptr, 0); + if (*endptr != '\0' || *retval < 0) + gold_fatal(_("%s: invalid option value (expected an integer): %s"), + option_name, arg); +} + +void +parse_int(const char* option_name, const char* arg, int* retval) +{ + char* endptr; + *retval = strtol(arg, &endptr, 0); + if (*endptr != '\0') + gold_fatal(_("%s: invalid option value (expected an integer): %s"), + option_name, arg); +} + +void +parse_uint64(const char* option_name, const char* arg, uint64_t* retval) +{ + char* endptr; + *retval = strtoull(arg, &endptr, 0); + if (*endptr != '\0') + gold_fatal(_("%s: invalid option value (expected an integer): %s"), + option_name, arg); +} + +void +parse_double(const char* option_name, const char* arg, double* retval) +{ + char* endptr; + *retval = strtod(arg, &endptr); + if (*endptr != '\0') + gold_fatal(_("%s: invalid option value " + "(expected a floating point number): %s"), + option_name, arg); +} + +void +parse_percent(const char* option_name, const char* arg, double* retval) +{ + char* endptr; + *retval = strtod(arg, &endptr) / 100.0; + if (*endptr != '\0') + gold_fatal(_("%s: invalid option value " + "(expected a floating point number): %s"), + option_name, arg); +} + +void +parse_string(const char* option_name, const char* arg, const char** retval) +{ + if (*arg == '\0') + gold_fatal(_("%s: must take a non-empty argument"), option_name); + *retval = arg; +} + +void +parse_optional_string(const char*, const char* arg, const char** retval) +{ + *retval = arg; +} + +void +parse_dirlist(const char*, const char* arg, Dir_list* retval) +{ + retval->push_back(Search_directory(arg, false)); +} + +void +parse_set(const char*, const char* arg, String_set* retval) +{ + retval->insert(std::string(arg)); +} + +void +parse_choices(const char* option_name, const char* arg, const char** retval, + const char* choices[], int num_choices) +{ + for (int i = 0; i < num_choices; i++) + if (strcmp(choices[i], arg) == 0) + { + *retval = arg; + return; + } + + // If we get here, the user did not enter a valid choice, so we die. + std::string choices_list; + for (int i = 0; i < num_choices; i++) + { + choices_list += choices[i]; + if (i != num_choices - 1) + choices_list += ", "; + } + gold_fatal(_("%s: must take one of the following arguments: %s"), + option_name, choices_list.c_str()); +} + +} // End namespace options. + +// Define the handler for "special" options (set via DEFINE_special). + +void +General_options::parse_help(const char*, const char*, Command_line*) +{ + options::help(); + ::exit(EXIT_SUCCESS); +} + +void +General_options::parse_version(const char* opt, const char*, Command_line*) +{ + bool print_short = (opt[0] == '-' && opt[1] == 'v'); + gold::print_version(print_short); + this->printed_version_ = true; + if (!print_short) + ::exit(EXIT_SUCCESS); +} + +void +General_options::parse_V(const char*, const char*, Command_line*) +{ + gold::print_version(true); + this->printed_version_ = true; + + printf(_(" Supported targets:\n")); + std::vector supported_names; + gold::supported_target_names(&supported_names); + for (std::vector::const_iterator p = supported_names.begin(); + p != supported_names.end(); + ++p) + printf(" %s\n", *p); + + printf(_(" Supported emulations:\n")); + supported_names.clear(); + gold::supported_emulation_names(&supported_names); + for (std::vector::const_iterator p = supported_names.begin(); + p != supported_names.end(); + ++p) + printf(" %s\n", *p); +} + +void +General_options::parse_defsym(const char*, const char* arg, + Command_line* cmdline) +{ + cmdline->script_options().define_symbol(arg); +} + +void +General_options::parse_incremental(const char*, const char*, + Command_line*) +{ + this->incremental_mode_ = INCREMENTAL_AUTO; +} + +void +General_options::parse_no_incremental(const char*, const char*, + Command_line*) +{ + this->incremental_mode_ = INCREMENTAL_OFF; +} + +void +General_options::parse_incremental_full(const char*, const char*, + Command_line*) +{ + this->incremental_mode_ = INCREMENTAL_FULL; +} + +void +General_options::parse_incremental_update(const char*, const char*, + Command_line*) +{ + this->incremental_mode_ = INCREMENTAL_UPDATE; +} + +void +General_options::parse_incremental_changed(const char*, const char*, + Command_line*) +{ + this->implicit_incremental_ = true; + this->incremental_disposition_ = INCREMENTAL_CHANGED; +} + +void +General_options::parse_incremental_unchanged(const char*, const char*, + Command_line*) +{ + this->implicit_incremental_ = true; + this->incremental_disposition_ = INCREMENTAL_UNCHANGED; +} + +void +General_options::parse_incremental_unknown(const char*, const char*, + Command_line*) +{ + this->implicit_incremental_ = true; + this->incremental_disposition_ = INCREMENTAL_CHECK; +} + +void +General_options::parse_incremental_startup_unchanged(const char*, const char*, + Command_line*) +{ + this->implicit_incremental_ = true; + this->incremental_startup_disposition_ = INCREMENTAL_UNCHANGED; +} + +void +General_options::parse_library(const char*, const char* arg, + Command_line* cmdline) +{ + Input_file_argument::Input_file_type type; + const char* name; + if (arg[0] == ':') + { + type = Input_file_argument::INPUT_FILE_TYPE_SEARCHED_FILE; + name = arg + 1; + } + else + { + type = Input_file_argument::INPUT_FILE_TYPE_LIBRARY; + name = arg; + } + Input_file_argument file(name, type, "", false, *this); + cmdline->inputs().add_file(file); +} + +#ifdef ENABLE_PLUGINS +void +General_options::parse_plugin(const char*, const char* arg, + Command_line*) +{ + this->add_plugin(arg); +} + +// Parse --plugin-opt. + +void +General_options::parse_plugin_opt(const char*, const char* arg, + Command_line*) +{ + this->add_plugin_option(arg); +} +#endif // ENABLE_PLUGINS + +void +General_options::parse_R(const char* option, const char* arg, + Command_line* cmdline) +{ + struct stat s; + if (::stat(arg, &s) != 0 || S_ISDIR(s.st_mode)) + this->add_to_rpath(arg); + else + this->parse_just_symbols(option, arg, cmdline); +} + +void +General_options::parse_just_symbols(const char*, const char* arg, + Command_line* cmdline) +{ + Input_file_argument file(arg, Input_file_argument::INPUT_FILE_TYPE_FILE, + "", true, *this); + cmdline->inputs().add_file(file); +} + +// Handle --section-start. + +void +General_options::parse_section_start(const char*, const char* arg, + Command_line*) +{ + const char* eq = strchr(arg, '='); + if (eq == NULL) + { + gold_error(_("invalid argument to --section-start; " + "must be SECTION=ADDRESS")); + return; + } + + std::string section_name(arg, eq - arg); + + ++eq; + const char* val_start = eq; + if (eq[0] == '0' && (eq[1] == 'x' || eq[1] == 'X')) + eq += 2; + if (*eq == '\0') + { + gold_error(_("--section-start address missing")); + return; + } + uint64_t addr = 0; + hex_init(); + for (; *eq != '\0'; ++eq) + { + if (!hex_p(*eq)) + { + gold_error(_("--section-start argument %s is not a valid hex number"), + val_start); + return; + } + addr <<= 4; + addr += hex_value(*eq); + } + + this->section_starts_[section_name] = addr; +} + +// Look up a --section-start value. + +bool +General_options::section_start(const char* secname, uint64_t* paddr) const +{ + if (this->section_starts_.empty()) + return false; + std::map::const_iterator p = + this->section_starts_.find(secname); + if (p == this->section_starts_.end()) + return false; + *paddr = p->second; + return true; +} + +void +General_options::parse_static(const char*, const char*, Command_line*) +{ + this->set_static(true); +} + +void +General_options::parse_script(const char*, const char* arg, + Command_line* cmdline) +{ + if (!read_commandline_script(arg, cmdline)) + gold::gold_fatal(_("unable to parse script file %s"), arg); +} + +void +General_options::parse_version_script(const char*, const char* arg, + Command_line* cmdline) +{ + if (!read_version_script(arg, cmdline)) + gold::gold_fatal(_("unable to parse version script file %s"), arg); +} + +void +General_options::parse_dynamic_list(const char*, const char* arg, + Command_line* cmdline) +{ + if (!read_dynamic_list(arg, cmdline, &this->dynamic_list_)) + gold::gold_fatal(_("unable to parse dynamic-list script file %s"), arg); +} + +void +General_options::parse_start_group(const char*, const char*, + Command_line* cmdline) +{ + cmdline->inputs().start_group(); +} + +void +General_options::parse_end_group(const char*, const char*, + Command_line* cmdline) +{ + cmdline->inputs().end_group(); +} + +void +General_options::parse_start_lib(const char*, const char*, + Command_line* cmdline) +{ + cmdline->inputs().start_lib(cmdline->position_dependent_options()); +} + +void +General_options::parse_end_lib(const char*, const char*, + Command_line* cmdline) +{ + cmdline->inputs().end_lib(); +} + +// The function add_excluded_libs() in ld/ldlang.c of GNU ld breaks up a list +// of names separated by commas or colons and puts them in a linked list. +// We implement the same parsing of names here but store names in an unordered +// map to speed up searching of names. + +void +General_options::parse_exclude_libs(const char*, const char* arg, + Command_line*) +{ + const char* p = arg; + + while (*p != '\0') + { + size_t length = strcspn(p, ",:"); + this->excluded_libs_.insert(std::string(p, length)); + p += (p[length] ? length + 1 : length); + } +} + +// The checking logic is based on the function check_excluded_libs() in +// ld/ldlang.c of GNU ld but our implementation is different because we use +// an unordered map instead of a linked list, which is what GNU ld uses. GNU +// ld searches sequentially in the excluded libs list. For a given archive, +// a match is found if the archive's name matches exactly one of the list +// entry or if the archive's name is of the form FOO.a and FOO matches exactly +// one of the list entry. An entry "ALL" in the list is considered as a +// wild-card and matches any given name. + +bool +General_options::check_excluded_libs(const std::string &name) const +{ + Unordered_set::const_iterator p; + + // Exit early for the most common case. + if (excluded_libs_.empty()) + return false; + + // If we see "ALL", all archives are excluded from automatic export. + p = excluded_libs_.find(std::string("ALL")); + if (p != excluded_libs_.end()) + return true; + + // First strip off any directories in name. + const char* basename = lbasename(name.c_str()); + + // Try finding an exact match. + p = excluded_libs_.find(std::string(basename)); + if (p != excluded_libs_.end()) + return true; + + // Try matching NAME without ".a" at the end. + size_t length = strlen(basename); + if ((length >= 2) + && (basename[length - 2] == '.') + && (basename[length - 1] == 'a')) + { + p = excluded_libs_.find(std::string(basename, length - 2)); + if (p != excluded_libs_.end()) + return true; + } + + return false; +} + +// Recognize input and output target names. The GNU linker accepts +// these with --format and --oformat. This code is intended to be +// minimally compatible. In practice for an ELF target this would be +// the same target as the input files; that name always start with +// "elf". Non-ELF targets would be "srec", "symbolsrec", "tekhex", +// "binary", "ihex". + +General_options::Object_format +General_options::string_to_object_format(const char* arg) +{ + if (strncmp(arg, "elf", 3) == 0 || strcmp(arg, "default") == 0) + return gold::General_options::OBJECT_FORMAT_ELF; + else if (strcmp(arg, "binary") == 0) + return gold::General_options::OBJECT_FORMAT_BINARY; + else + { + gold::gold_error(_("format '%s' not supported; treating as elf " + "(supported formats: elf, binary)"), + arg); + return gold::General_options::OBJECT_FORMAT_ELF; + } +} + +void +General_options::parse_fix_v4bx(const char*, const char*, + Command_line*) +{ + this->fix_v4bx_ = FIX_V4BX_REPLACE; +} + +void +General_options::parse_fix_v4bx_interworking(const char*, const char*, + Command_line*) +{ + this->fix_v4bx_ = FIX_V4BX_INTERWORKING; +} + +void +General_options::parse_EB(const char*, const char*, Command_line*) +{ + this->endianness_ = ENDIANNESS_BIG; +} + +void +General_options::parse_EL(const char*, const char*, Command_line*) +{ + this->endianness_ = ENDIANNESS_LITTLE; +} + +} // End namespace gold. + +namespace +{ + +void +usage() +{ + fprintf(stderr, + _("%s: use the --help option for usage information\n"), + gold::program_name); + ::exit(EXIT_FAILURE); +} + +void +usage(const char* msg, const char* opt) +{ + fprintf(stderr, + _("%s: %s: %s\n"), + gold::program_name, opt, msg); + usage(); +} + +// If the default sysroot is relocatable, try relocating it based on +// the prefix FROM. + +static char* +get_relative_sysroot(const char* from) +{ + char* path = make_relative_prefix(gold::program_name, from, + TARGET_SYSTEM_ROOT); + if (path != NULL) + { + struct stat s; + if (::stat(path, &s) == 0 && S_ISDIR(s.st_mode)) + return path; + free(path); + } + + return NULL; +} + +// Return the default sysroot. This is set by the --with-sysroot +// option to configure. Note we do not free the return value of +// get_relative_sysroot, which is a small memory leak, but is +// necessary since we store this pointer directly in General_options. + +static const char* +get_default_sysroot() +{ + const char* sysroot = TARGET_SYSTEM_ROOT; + if (*sysroot == '\0') + return NULL; + + if (TARGET_SYSTEM_ROOT_RELOCATABLE) + { + char* path = get_relative_sysroot(BINDIR); + if (path == NULL) + path = get_relative_sysroot(TOOLBINDIR); + if (path != NULL) + return path; + } + + return sysroot; +} + +// Parse a long option. Such options have the form +// <-|-->